1 // Copyright 2014 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/input_method_chromeos.h" 6 7 #include <X11/Xlib.h> 8 #undef Bool 9 #undef FocusIn 10 #undef FocusOut 11 #undef None 12 13 #include <cstring> 14 15 #include "base/i18n/char_iterator.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/strings/utf_string_conversions.h" 18 #include "chromeos/ime/composition_text.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "ui/base/ime/chromeos/ime_bridge.h" 21 #include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h" 22 #include "ui/base/ime/chromeos/mock_ime_engine_handler.h" 23 #include "ui/base/ime/input_method_delegate.h" 24 #include "ui/base/ime/text_input_client.h" 25 #include "ui/base/ime/text_input_focus_manager.h" 26 #include "ui/base/ui_base_switches_util.h" 27 #include "ui/events/event.h" 28 #include "ui/events/test/events_test_utils_x11.h" 29 #include "ui/gfx/geometry/rect.h" 30 31 using base::UTF8ToUTF16; 32 using base::UTF16ToUTF8; 33 34 namespace ui { 35 namespace { 36 37 const base::string16 kSampleText = base::UTF8ToUTF16( 38 "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86\xE3\x81\x88\xE3\x81\x8A"); 39 40 typedef chromeos::IMEEngineHandlerInterface::KeyEventDoneCallback 41 KeyEventCallback; 42 43 uint32 GetOffsetInUTF16( 44 const base::string16& utf16_string, uint32 utf8_offset) { 45 DCHECK_LT(utf8_offset, utf16_string.size()); 46 base::i18n::UTF16CharIterator char_iterator(&utf16_string); 47 for (size_t i = 0; i < utf8_offset; ++i) 48 char_iterator.Advance(); 49 return char_iterator.array_pos(); 50 } 51 52 bool IsEqualXKeyEvent(const XEvent& e1, const XEvent& e2) { 53 if ((e1.type == KeyPress && e2.type == KeyPress) || 54 (e1.type == KeyRelease && e2.type == KeyRelease)) { 55 return !std::memcmp(&e1.xkey, &e2.xkey, sizeof(XKeyEvent)); 56 } 57 return false; 58 } 59 60 enum KeyEventHandlerBehavior { 61 KEYEVENT_CONSUME, 62 KEYEVENT_NOT_CONSUME, 63 }; 64 65 } // namespace 66 67 68 class TestableInputMethodChromeOS : public InputMethodChromeOS { 69 public: 70 explicit TestableInputMethodChromeOS(internal::InputMethodDelegate* delegate) 71 : InputMethodChromeOS(delegate), 72 process_key_event_post_ime_call_count_(0) { 73 } 74 75 struct ProcessKeyEventPostIMEArgs { 76 ProcessKeyEventPostIMEArgs() : event(NULL), handled(false) {} 77 const ui::KeyEvent* event; 78 bool handled; 79 }; 80 81 // Overridden from InputMethodChromeOS: 82 virtual void ProcessKeyEventPostIME(const ui::KeyEvent& key_event, 83 bool handled) OVERRIDE { 84 process_key_event_post_ime_args_.event = &key_event; 85 process_key_event_post_ime_args_.handled = handled; 86 ++process_key_event_post_ime_call_count_; 87 } 88 89 void ResetCallCount() { 90 process_key_event_post_ime_call_count_ = 0; 91 } 92 93 const ProcessKeyEventPostIMEArgs& process_key_event_post_ime_args() const { 94 return process_key_event_post_ime_args_; 95 } 96 97 int process_key_event_post_ime_call_count() const { 98 return process_key_event_post_ime_call_count_; 99 } 100 101 // Change access rights for testing. 102 using InputMethodChromeOS::ExtractCompositionText; 103 using InputMethodChromeOS::ResetContext; 104 105 private: 106 ProcessKeyEventPostIMEArgs process_key_event_post_ime_args_; 107 int process_key_event_post_ime_call_count_; 108 }; 109 110 class SynchronousKeyEventHandler { 111 public: 112 SynchronousKeyEventHandler(uint32 expected_keyval, 113 uint32 expected_keycode, 114 uint32 expected_state, 115 KeyEventHandlerBehavior behavior) 116 : expected_keyval_(expected_keyval), 117 expected_keycode_(expected_keycode), 118 expected_state_(expected_state), 119 behavior_(behavior) {} 120 121 virtual ~SynchronousKeyEventHandler() {} 122 123 void Run(uint32 keyval, 124 uint32 keycode, 125 uint32 state, 126 const KeyEventCallback& callback) { 127 EXPECT_EQ(expected_keyval_, keyval); 128 EXPECT_EQ(expected_keycode_, keycode); 129 EXPECT_EQ(expected_state_, state); 130 callback.Run(behavior_ == KEYEVENT_CONSUME); 131 } 132 133 private: 134 const uint32 expected_keyval_; 135 const uint32 expected_keycode_; 136 const uint32 expected_state_; 137 const KeyEventHandlerBehavior behavior_; 138 139 DISALLOW_COPY_AND_ASSIGN(SynchronousKeyEventHandler); 140 }; 141 142 class AsynchronousKeyEventHandler { 143 public: 144 AsynchronousKeyEventHandler(uint32 expected_keyval, 145 uint32 expected_keycode, 146 uint32 expected_state) 147 : expected_keyval_(expected_keyval), 148 expected_keycode_(expected_keycode), 149 expected_state_(expected_state) {} 150 151 virtual ~AsynchronousKeyEventHandler() {} 152 153 void Run(uint32 keyval, 154 uint32 keycode, 155 uint32 state, 156 const KeyEventCallback& callback) { 157 EXPECT_EQ(expected_keyval_, keyval); 158 EXPECT_EQ(expected_keycode_, keycode); 159 EXPECT_EQ(expected_state_, state); 160 callback_ = callback; 161 } 162 163 void RunCallback(KeyEventHandlerBehavior behavior) { 164 callback_.Run(behavior == KEYEVENT_CONSUME); 165 } 166 167 private: 168 const uint32 expected_keyval_; 169 const uint32 expected_keycode_; 170 const uint32 expected_state_; 171 KeyEventCallback callback_; 172 173 DISALLOW_COPY_AND_ASSIGN(AsynchronousKeyEventHandler); 174 }; 175 176 class SetSurroundingTextVerifier { 177 public: 178 SetSurroundingTextVerifier(const std::string& expected_surrounding_text, 179 uint32 expected_cursor_position, 180 uint32 expected_anchor_position) 181 : expected_surrounding_text_(expected_surrounding_text), 182 expected_cursor_position_(expected_cursor_position), 183 expected_anchor_position_(expected_anchor_position) {} 184 185 void Verify(const std::string& text, 186 uint32 cursor_pos, 187 uint32 anchor_pos) { 188 EXPECT_EQ(expected_surrounding_text_, text); 189 EXPECT_EQ(expected_cursor_position_, cursor_pos); 190 EXPECT_EQ(expected_anchor_position_, anchor_pos); 191 } 192 193 private: 194 const std::string expected_surrounding_text_; 195 const uint32 expected_cursor_position_; 196 const uint32 expected_anchor_position_; 197 198 DISALLOW_COPY_AND_ASSIGN(SetSurroundingTextVerifier); 199 }; 200 201 class InputMethodChromeOSTest : public internal::InputMethodDelegate, 202 public testing::Test, 203 public TextInputClient { 204 public: 205 InputMethodChromeOSTest() 206 : dispatched_key_event_(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, ui::EF_NONE) { 207 ResetFlags(); 208 } 209 210 virtual ~InputMethodChromeOSTest() { 211 } 212 213 virtual void SetUp() OVERRIDE { 214 chromeos::IMEBridge::Initialize(); 215 216 mock_ime_engine_handler_.reset( 217 new chromeos::MockIMEEngineHandler()); 218 chromeos::IMEBridge::Get()->SetCurrentEngineHandler( 219 mock_ime_engine_handler_.get()); 220 221 mock_ime_candidate_window_handler_.reset( 222 new chromeos::MockIMECandidateWindowHandler()); 223 chromeos::IMEBridge::Get()->SetCandidateWindowHandler( 224 mock_ime_candidate_window_handler_.get()); 225 226 ime_.reset(new TestableInputMethodChromeOS(this)); 227 if (switches::IsTextInputFocusManagerEnabled()) 228 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); 229 else 230 ime_->SetFocusedTextInputClient(this); 231 } 232 233 virtual void TearDown() OVERRIDE { 234 if (ime_.get()) { 235 if (switches::IsTextInputFocusManagerEnabled()) 236 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); 237 else 238 ime_->SetFocusedTextInputClient(NULL); 239 } 240 ime_.reset(); 241 chromeos::IMEBridge::Get()->SetCurrentEngineHandler(NULL); 242 chromeos::IMEBridge::Get()->SetCandidateWindowHandler(NULL); 243 mock_ime_engine_handler_.reset(); 244 mock_ime_candidate_window_handler_.reset(); 245 chromeos::IMEBridge::Shutdown(); 246 } 247 248 // Overridden from ui::internal::InputMethodDelegate: 249 virtual bool DispatchKeyEventPostIME(const ui::KeyEvent& event) OVERRIDE { 250 dispatched_key_event_ = event; 251 return false; 252 } 253 254 // Overridden from ui::TextInputClient: 255 virtual void SetCompositionText( 256 const CompositionText& composition) OVERRIDE { 257 composition_text_ = composition; 258 } 259 virtual void ConfirmCompositionText() OVERRIDE { 260 confirmed_text_ = composition_text_; 261 composition_text_.Clear(); 262 } 263 virtual void ClearCompositionText() OVERRIDE { 264 composition_text_.Clear(); 265 } 266 virtual void InsertText(const base::string16& text) OVERRIDE { 267 inserted_text_ = text; 268 } 269 virtual void InsertChar(base::char16 ch, int flags) OVERRIDE { 270 inserted_char_ = ch; 271 inserted_char_flags_ = flags; 272 } 273 virtual gfx::NativeWindow GetAttachedWindow() const OVERRIDE { 274 return static_cast<gfx::NativeWindow>(NULL); 275 } 276 virtual TextInputType GetTextInputType() const OVERRIDE { 277 return input_type_; 278 } 279 virtual TextInputMode GetTextInputMode() const OVERRIDE { 280 return input_mode_; 281 } 282 virtual bool CanComposeInline() const OVERRIDE { 283 return can_compose_inline_; 284 } 285 virtual gfx::Rect GetCaretBounds() const OVERRIDE { 286 return caret_bounds_; 287 } 288 virtual bool GetCompositionCharacterBounds(uint32 index, 289 gfx::Rect* rect) const OVERRIDE { 290 return false; 291 } 292 virtual bool HasCompositionText() const OVERRIDE { 293 CompositionText empty; 294 return composition_text_ != empty; 295 } 296 virtual bool GetTextRange(gfx::Range* range) const OVERRIDE { 297 *range = text_range_; 298 return true; 299 } 300 virtual bool GetCompositionTextRange(gfx::Range* range) const OVERRIDE { 301 return false; 302 } 303 virtual bool GetSelectionRange(gfx::Range* range) const OVERRIDE { 304 *range = selection_range_; 305 return true; 306 } 307 308 virtual bool SetSelectionRange(const gfx::Range& range) OVERRIDE { 309 return false; 310 } 311 virtual bool DeleteRange(const gfx::Range& range) OVERRIDE { return false; } 312 virtual bool GetTextFromRange(const gfx::Range& range, 313 base::string16* text) const OVERRIDE { 314 *text = surrounding_text_.substr(range.GetMin(), range.length()); 315 return true; 316 } 317 virtual void OnInputMethodChanged() OVERRIDE { 318 ++on_input_method_changed_call_count_; 319 } 320 virtual bool ChangeTextDirectionAndLayoutAlignment( 321 base::i18n::TextDirection direction) OVERRIDE { return false; } 322 virtual void ExtendSelectionAndDelete(size_t before, 323 size_t after) OVERRIDE {} 324 virtual void EnsureCaretInRect(const gfx::Rect& rect) OVERRIDE {} 325 virtual void OnCandidateWindowShown() OVERRIDE {} 326 virtual void OnCandidateWindowUpdated() OVERRIDE {} 327 virtual void OnCandidateWindowHidden() OVERRIDE {} 328 virtual bool IsEditingCommandEnabled(int command_id) OVERRIDE { 329 return false; 330 } 331 virtual void ExecuteEditingCommand(int command_id) OVERRIDE {} 332 333 bool HasNativeEvent() const { 334 return dispatched_key_event_.HasNativeEvent(); 335 } 336 337 void ResetFlags() { 338 dispatched_key_event_ = ui::KeyEvent(ui::ET_UNKNOWN, ui::VKEY_UNKNOWN, 339 ui::EF_NONE); 340 341 composition_text_.Clear(); 342 confirmed_text_.Clear(); 343 inserted_text_.clear(); 344 inserted_char_ = 0; 345 inserted_char_flags_ = 0; 346 on_input_method_changed_call_count_ = 0; 347 348 input_type_ = TEXT_INPUT_TYPE_NONE; 349 input_mode_ = TEXT_INPUT_MODE_DEFAULT; 350 can_compose_inline_ = true; 351 caret_bounds_ = gfx::Rect(); 352 } 353 354 scoped_ptr<TestableInputMethodChromeOS> ime_; 355 356 // Copy of the dispatched key event. 357 ui::KeyEvent dispatched_key_event_; 358 359 // Variables for remembering the parameters that are passed to 360 // ui::TextInputClient functions. 361 CompositionText composition_text_; 362 CompositionText confirmed_text_; 363 base::string16 inserted_text_; 364 base::char16 inserted_char_; 365 unsigned int on_input_method_changed_call_count_; 366 int inserted_char_flags_; 367 368 // Variables that will be returned from the ui::TextInputClient functions. 369 TextInputType input_type_; 370 TextInputMode input_mode_; 371 bool can_compose_inline_; 372 gfx::Rect caret_bounds_; 373 gfx::Range text_range_; 374 gfx::Range selection_range_; 375 base::string16 surrounding_text_; 376 377 scoped_ptr<chromeos::MockIMEEngineHandler> mock_ime_engine_handler_; 378 scoped_ptr<chromeos::MockIMECandidateWindowHandler> 379 mock_ime_candidate_window_handler_; 380 381 DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSTest); 382 }; 383 384 // Tests public APIs in ui::InputMethod first. 385 386 TEST_F(InputMethodChromeOSTest, GetInputLocale) { 387 // ui::InputMethodChromeOS does not support the API. 388 ime_->Init(true); 389 EXPECT_EQ("", ime_->GetInputLocale()); 390 } 391 392 TEST_F(InputMethodChromeOSTest, IsActive) { 393 ime_->Init(true); 394 // ui::InputMethodChromeOS always returns true. 395 EXPECT_TRUE(ime_->IsActive()); 396 } 397 398 TEST_F(InputMethodChromeOSTest, GetInputTextType) { 399 ime_->Init(true); 400 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 401 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 402 ime_->OnTextInputTypeChanged(this); 403 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); 404 input_type_ = TEXT_INPUT_TYPE_TEXT; 405 ime_->OnTextInputTypeChanged(this); 406 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, ime_->GetTextInputType()); 407 } 408 409 TEST_F(InputMethodChromeOSTest, CanComposeInline) { 410 ime_->Init(true); 411 EXPECT_TRUE(ime_->CanComposeInline()); 412 can_compose_inline_ = false; 413 ime_->OnTextInputTypeChanged(this); 414 EXPECT_FALSE(ime_->CanComposeInline()); 415 } 416 417 TEST_F(InputMethodChromeOSTest, GetTextInputClient) { 418 ime_->Init(true); 419 EXPECT_EQ(this, ime_->GetTextInputClient()); 420 if (switches::IsTextInputFocusManagerEnabled()) 421 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); 422 else 423 ime_->SetFocusedTextInputClient(NULL); 424 EXPECT_EQ(NULL, ime_->GetTextInputClient()); 425 } 426 427 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedClient) { 428 ime_->Init(true); 429 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 430 if (switches::IsTextInputFocusManagerEnabled()) 431 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); 432 else 433 ime_->SetFocusedTextInputClient(NULL); 434 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 435 ime_->OnTextInputTypeChanged(this); 436 // The OnTextInputTypeChanged() call above should be ignored since |this| is 437 // not the current focused client. 438 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 439 440 if (switches::IsTextInputFocusManagerEnabled()) 441 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); 442 else 443 ime_->SetFocusedTextInputClient(this); 444 ime_->OnTextInputTypeChanged(this); 445 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); 446 } 447 448 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow) { 449 ime_->Init(true); 450 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 451 if (switches::IsTextInputFocusManagerEnabled()) 452 TextInputFocusManager::GetInstance()->BlurTextInputClient(this); 453 else 454 ime_->OnBlur(); 455 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 456 ime_->OnTextInputTypeChanged(this); 457 // The OnTextInputTypeChanged() call above should be ignored since the top- 458 // level window which the ime_ is attached to is not currently focused. 459 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 460 461 if (switches::IsTextInputFocusManagerEnabled()) 462 TextInputFocusManager::GetInstance()->FocusTextInputClient(this); 463 else 464 ime_->OnFocus(); 465 ime_->OnTextInputTypeChanged(this); 466 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); 467 } 468 469 TEST_F(InputMethodChromeOSTest, GetInputTextType_WithoutFocusedWindow2) { 470 // We no longer support the case that |ime_->Init(false)| because no one 471 // actually uses it. 472 if (switches::IsTextInputFocusManagerEnabled()) 473 return; 474 475 ime_->Init(false); // the top-level is initially unfocused. 476 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 477 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 478 ime_->OnTextInputTypeChanged(this); 479 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, ime_->GetTextInputType()); 480 481 ime_->OnFocus(); 482 ime_->OnTextInputTypeChanged(this); 483 EXPECT_EQ(TEXT_INPUT_TYPE_PASSWORD, ime_->GetTextInputType()); 484 } 485 486 // Confirm that IBusClient::FocusIn is called on "connected" if input_type_ is 487 // TEXT. 488 TEST_F(InputMethodChromeOSTest, FocusIn_Text) { 489 ime_->Init(true); 490 // A context shouldn't be created since the daemon is not running. 491 EXPECT_EQ(0U, on_input_method_changed_call_count_); 492 // Click a text input form. 493 input_type_ = TEXT_INPUT_TYPE_TEXT; 494 ime_->OnTextInputTypeChanged(this); 495 // Since a form has focus, IBusClient::FocusIn() should be called. 496 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 497 EXPECT_EQ( 498 1, 499 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); 500 // ui::TextInputClient::OnInputMethodChanged() should be called when 501 // ui::InputMethodChromeOS connects/disconnects to/from ibus-daemon and the 502 // current text input type is not NONE. 503 EXPECT_EQ(1U, on_input_method_changed_call_count_); 504 } 505 506 // Confirm that InputMethodEngine::FocusIn is called on "connected" even if 507 // input_type_ is PASSWORD. 508 TEST_F(InputMethodChromeOSTest, FocusIn_Password) { 509 ime_->Init(true); 510 EXPECT_EQ(0U, on_input_method_changed_call_count_); 511 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 512 ime_->OnTextInputTypeChanged(this); 513 // InputMethodEngine::FocusIn() should be called even for password field. 514 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 515 EXPECT_EQ(1U, on_input_method_changed_call_count_); 516 } 517 518 // Confirm that IBusClient::FocusOut is called as expected. 519 TEST_F(InputMethodChromeOSTest, FocusOut_None) { 520 input_type_ = TEXT_INPUT_TYPE_TEXT; 521 ime_->Init(true); 522 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 523 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); 524 input_type_ = TEXT_INPUT_TYPE_NONE; 525 ime_->OnTextInputTypeChanged(this); 526 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 527 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); 528 } 529 530 // Confirm that IBusClient::FocusOut is called as expected. 531 TEST_F(InputMethodChromeOSTest, FocusOut_Password) { 532 input_type_ = TEXT_INPUT_TYPE_TEXT; 533 ime_->Init(true); 534 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 535 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); 536 input_type_ = TEXT_INPUT_TYPE_PASSWORD; 537 ime_->OnTextInputTypeChanged(this); 538 EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count()); 539 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); 540 } 541 542 // FocusIn/FocusOut scenario test 543 TEST_F(InputMethodChromeOSTest, Focus_Scenario) { 544 ime_->Init(true); 545 // Confirm that both FocusIn and FocusOut are NOT called. 546 EXPECT_EQ(0, mock_ime_engine_handler_->focus_in_call_count()); 547 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); 548 EXPECT_EQ(TEXT_INPUT_TYPE_NONE, 549 mock_ime_engine_handler_->last_text_input_context().type); 550 EXPECT_EQ(TEXT_INPUT_MODE_DEFAULT, 551 mock_ime_engine_handler_->last_text_input_context().mode); 552 553 input_type_ = TEXT_INPUT_TYPE_TEXT; 554 input_mode_ = TEXT_INPUT_MODE_LATIN; 555 ime_->OnTextInputTypeChanged(this); 556 // Confirm that only FocusIn is called, the TextInputType is TEXT and the 557 // TextInputMode is LATIN.. 558 EXPECT_EQ(1, mock_ime_engine_handler_->focus_in_call_count()); 559 EXPECT_EQ(0, mock_ime_engine_handler_->focus_out_call_count()); 560 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, 561 mock_ime_engine_handler_->last_text_input_context().type); 562 EXPECT_EQ(TEXT_INPUT_MODE_LATIN, 563 mock_ime_engine_handler_->last_text_input_context().mode); 564 565 input_mode_ = TEXT_INPUT_MODE_KANA; 566 ime_->OnTextInputTypeChanged(this); 567 // Confirm that both FocusIn and FocusOut are called for mode change. 568 EXPECT_EQ(2, mock_ime_engine_handler_->focus_in_call_count()); 569 EXPECT_EQ(1, mock_ime_engine_handler_->focus_out_call_count()); 570 EXPECT_EQ(TEXT_INPUT_TYPE_TEXT, 571 mock_ime_engine_handler_->last_text_input_context().type); 572 EXPECT_EQ(TEXT_INPUT_MODE_KANA, 573 mock_ime_engine_handler_->last_text_input_context().mode); 574 575 input_type_ = TEXT_INPUT_TYPE_URL; 576 ime_->OnTextInputTypeChanged(this); 577 // Confirm that both FocusIn and FocusOut are called and the TextInputType is 578 // changed to URL. 579 EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count()); 580 EXPECT_EQ(2, mock_ime_engine_handler_->focus_out_call_count()); 581 EXPECT_EQ(TEXT_INPUT_TYPE_URL, 582 mock_ime_engine_handler_->last_text_input_context().type); 583 EXPECT_EQ(TEXT_INPUT_MODE_KANA, 584 mock_ime_engine_handler_->last_text_input_context().mode); 585 586 // When IsTextInputFocusManagerEnabled, InputMethod::SetFocusedTextInputClient 587 // is not supported and it's no-op. 588 if (switches::IsTextInputFocusManagerEnabled()) 589 return; 590 // Confirm that FocusOut is called when set focus to NULL client. 591 ime_->SetFocusedTextInputClient(NULL); 592 EXPECT_EQ(3, mock_ime_engine_handler_->focus_in_call_count()); 593 EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count()); 594 // Confirm that FocusIn is called when set focus to this client. 595 ime_->SetFocusedTextInputClient(this); 596 EXPECT_EQ(4, mock_ime_engine_handler_->focus_in_call_count()); 597 EXPECT_EQ(3, mock_ime_engine_handler_->focus_out_call_count()); 598 } 599 600 // Test if the new |caret_bounds_| is correctly sent to ibus-daemon. 601 TEST_F(InputMethodChromeOSTest, OnCaretBoundsChanged) { 602 input_type_ = TEXT_INPUT_TYPE_TEXT; 603 ime_->Init(true); 604 EXPECT_EQ( 605 1, 606 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); 607 caret_bounds_ = gfx::Rect(1, 2, 3, 4); 608 ime_->OnCaretBoundsChanged(this); 609 EXPECT_EQ( 610 2, 611 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); 612 caret_bounds_ = gfx::Rect(0, 2, 3, 4); 613 ime_->OnCaretBoundsChanged(this); 614 EXPECT_EQ( 615 3, 616 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); 617 caret_bounds_ = gfx::Rect(0, 2, 3, 4); // unchanged 618 ime_->OnCaretBoundsChanged(this); 619 // Current InputMethodChromeOS implementation performs the IPC 620 // regardless of the bounds are changed or not. 621 EXPECT_EQ( 622 4, 623 mock_ime_candidate_window_handler_->set_cursor_bounds_call_count()); 624 } 625 626 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_NoAttribute) { 627 const base::string16 kSampleAsciiText = UTF8ToUTF16("Sample Text"); 628 const uint32 kCursorPos = 2UL; 629 630 chromeos::CompositionText chromeos_composition_text; 631 chromeos_composition_text.set_text(kSampleAsciiText); 632 633 CompositionText composition_text; 634 ime_->ExtractCompositionText( 635 chromeos_composition_text, kCursorPos, &composition_text); 636 EXPECT_EQ(kSampleAsciiText, composition_text.text); 637 // If there is no selection, |selection| represents cursor position. 638 EXPECT_EQ(kCursorPos, composition_text.selection.start()); 639 EXPECT_EQ(kCursorPos, composition_text.selection.end()); 640 // If there is no underline, |underlines| contains one underline and it is 641 // whole text underline. 642 ASSERT_EQ(1UL, composition_text.underlines.size()); 643 EXPECT_EQ(0UL, composition_text.underlines[0].start_offset); 644 EXPECT_EQ(kSampleAsciiText.size(), composition_text.underlines[0].end_offset); 645 EXPECT_FALSE(composition_text.underlines[0].thick); 646 } 647 648 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_SingleUnderline) { 649 const uint32 kCursorPos = 2UL; 650 651 // Set up chromeos composition text with one underline attribute. 652 chromeos::CompositionText chromeos_composition_text; 653 chromeos_composition_text.set_text(kSampleText); 654 chromeos::CompositionText::UnderlineAttribute underline; 655 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_SINGLE; 656 underline.start_index = 1UL; 657 underline.end_index = 4UL; 658 chromeos_composition_text.mutable_underline_attributes()->push_back( 659 underline); 660 661 CompositionText composition_text; 662 ime_->ExtractCompositionText( 663 chromeos_composition_text, kCursorPos, &composition_text); 664 EXPECT_EQ(kSampleText, composition_text.text); 665 // If there is no selection, |selection| represents cursor position. 666 EXPECT_EQ(kCursorPos, composition_text.selection.start()); 667 EXPECT_EQ(kCursorPos, composition_text.selection.end()); 668 ASSERT_EQ(1UL, composition_text.underlines.size()); 669 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), 670 composition_text.underlines[0].start_offset); 671 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), 672 composition_text.underlines[0].end_offset); 673 // Single underline represents as black thin line. 674 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); 675 EXPECT_FALSE(composition_text.underlines[0].thick); 676 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), 677 composition_text.underlines[0].background_color); 678 } 679 680 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_DoubleUnderline) { 681 const uint32 kCursorPos = 2UL; 682 683 // Set up chromeos composition text with one underline attribute. 684 chromeos::CompositionText chromeos_composition_text; 685 chromeos_composition_text.set_text(kSampleText); 686 chromeos::CompositionText::UnderlineAttribute underline; 687 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE; 688 underline.start_index = 1UL; 689 underline.end_index = 4UL; 690 chromeos_composition_text.mutable_underline_attributes()->push_back( 691 underline); 692 693 CompositionText composition_text; 694 ime_->ExtractCompositionText( 695 chromeos_composition_text, kCursorPos, &composition_text); 696 EXPECT_EQ(kSampleText, composition_text.text); 697 // If there is no selection, |selection| represents cursor position. 698 EXPECT_EQ(kCursorPos, composition_text.selection.start()); 699 EXPECT_EQ(kCursorPos, composition_text.selection.end()); 700 ASSERT_EQ(1UL, composition_text.underlines.size()); 701 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), 702 composition_text.underlines[0].start_offset); 703 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), 704 composition_text.underlines[0].end_offset); 705 // Double underline represents as black thick line. 706 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); 707 EXPECT_TRUE(composition_text.underlines[0].thick); 708 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), 709 composition_text.underlines[0].background_color); 710 } 711 712 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_ErrorUnderline) { 713 const uint32 kCursorPos = 2UL; 714 715 // Set up chromeos composition text with one underline attribute. 716 chromeos::CompositionText chromeos_composition_text; 717 chromeos_composition_text.set_text(kSampleText); 718 chromeos::CompositionText::UnderlineAttribute underline; 719 underline.type = chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_ERROR; 720 underline.start_index = 1UL; 721 underline.end_index = 4UL; 722 chromeos_composition_text.mutable_underline_attributes()->push_back( 723 underline); 724 725 CompositionText composition_text; 726 ime_->ExtractCompositionText( 727 chromeos_composition_text, kCursorPos, &composition_text); 728 EXPECT_EQ(kSampleText, composition_text.text); 729 EXPECT_EQ(kCursorPos, composition_text.selection.start()); 730 EXPECT_EQ(kCursorPos, composition_text.selection.end()); 731 ASSERT_EQ(1UL, composition_text.underlines.size()); 732 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.start_index), 733 composition_text.underlines[0].start_offset); 734 EXPECT_EQ(GetOffsetInUTF16(kSampleText, underline.end_index), 735 composition_text.underlines[0].end_offset); 736 // Error underline represents as red thin line. 737 EXPECT_EQ(SK_ColorRED, composition_text.underlines[0].color); 738 EXPECT_FALSE(composition_text.underlines[0].thick); 739 } 740 741 TEST_F(InputMethodChromeOSTest, ExtractCompositionTextTest_Selection) { 742 const uint32 kCursorPos = 2UL; 743 744 // Set up chromeos composition text with one underline attribute. 745 chromeos::CompositionText chromeos_composition_text; 746 chromeos_composition_text.set_text(kSampleText); 747 chromeos_composition_text.set_selection_start(1UL); 748 chromeos_composition_text.set_selection_end(4UL); 749 750 CompositionText composition_text; 751 ime_->ExtractCompositionText( 752 chromeos_composition_text, kCursorPos, &composition_text); 753 EXPECT_EQ(kSampleText, composition_text.text); 754 EXPECT_EQ(kCursorPos, composition_text.selection.start()); 755 EXPECT_EQ(kCursorPos, composition_text.selection.end()); 756 ASSERT_EQ(1UL, composition_text.underlines.size()); 757 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 758 chromeos_composition_text.selection_start()), 759 composition_text.underlines[0].start_offset); 760 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 761 chromeos_composition_text.selection_end()), 762 composition_text.underlines[0].end_offset); 763 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); 764 EXPECT_TRUE(composition_text.underlines[0].thick); 765 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), 766 composition_text.underlines[0].background_color); 767 } 768 769 TEST_F(InputMethodChromeOSTest, 770 ExtractCompositionTextTest_SelectionStartWithCursor) { 771 const uint32 kCursorPos = 1UL; 772 773 // Set up chromeos composition text with one underline attribute. 774 chromeos::CompositionText chromeos_composition_text; 775 chromeos_composition_text.set_text(kSampleText); 776 chromeos_composition_text.set_selection_start(kCursorPos); 777 chromeos_composition_text.set_selection_end(4UL); 778 779 CompositionText composition_text; 780 ime_->ExtractCompositionText( 781 chromeos_composition_text, kCursorPos, &composition_text); 782 EXPECT_EQ(kSampleText, composition_text.text); 783 // If the cursor position is same as selection bounds, selection start 784 // position become opposit side of selection from cursor. 785 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 786 chromeos_composition_text.selection_end()), 787 composition_text.selection.start()); 788 EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), 789 composition_text.selection.end()); 790 ASSERT_EQ(1UL, composition_text.underlines.size()); 791 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 792 chromeos_composition_text.selection_start()), 793 composition_text.underlines[0].start_offset); 794 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 795 chromeos_composition_text.selection_end()), 796 composition_text.underlines[0].end_offset); 797 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); 798 EXPECT_TRUE(composition_text.underlines[0].thick); 799 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), 800 composition_text.underlines[0].background_color); 801 } 802 803 TEST_F(InputMethodChromeOSTest, 804 ExtractCompositionTextTest_SelectionEndWithCursor) { 805 const uint32 kCursorPos = 4UL; 806 807 // Set up chromeos composition text with one underline attribute. 808 chromeos::CompositionText chromeos_composition_text; 809 chromeos_composition_text.set_text(kSampleText); 810 chromeos_composition_text.set_selection_start(1UL); 811 chromeos_composition_text.set_selection_end(kCursorPos); 812 813 CompositionText composition_text; 814 ime_->ExtractCompositionText( 815 chromeos_composition_text, kCursorPos, &composition_text); 816 EXPECT_EQ(kSampleText, composition_text.text); 817 // If the cursor position is same as selection bounds, selection start 818 // position become opposit side of selection from cursor. 819 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 820 chromeos_composition_text.selection_start()), 821 composition_text.selection.start()); 822 EXPECT_EQ(GetOffsetInUTF16(kSampleText, kCursorPos), 823 composition_text.selection.end()); 824 ASSERT_EQ(1UL, composition_text.underlines.size()); 825 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 826 chromeos_composition_text.selection_start()), 827 composition_text.underlines[0].start_offset); 828 EXPECT_EQ(GetOffsetInUTF16(kSampleText, 829 chromeos_composition_text.selection_end()), 830 composition_text.underlines[0].end_offset); 831 EXPECT_EQ(SK_ColorBLACK, composition_text.underlines[0].color); 832 EXPECT_TRUE(composition_text.underlines[0].thick); 833 EXPECT_EQ(static_cast<SkColor>(SK_ColorTRANSPARENT), 834 composition_text.underlines[0].background_color); 835 } 836 837 TEST_F(InputMethodChromeOSTest, SurroundingText_NoSelectionTest) { 838 ime_->Init(true); 839 // Click a text input form. 840 input_type_ = TEXT_INPUT_TYPE_TEXT; 841 ime_->OnTextInputTypeChanged(this); 842 843 // Set the TextInputClient behaviors. 844 surrounding_text_ = UTF8ToUTF16("abcdef"); 845 text_range_ = gfx::Range(0, 6); 846 selection_range_ = gfx::Range(3, 3); 847 848 // Set the verifier for SetSurroundingText mock call. 849 SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 3, 3); 850 851 852 ime_->OnCaretBoundsChanged(this); 853 854 // Check the call count. 855 EXPECT_EQ(1, 856 mock_ime_engine_handler_->set_surrounding_text_call_count()); 857 EXPECT_EQ(UTF16ToUTF8(surrounding_text_), 858 mock_ime_engine_handler_->last_set_surrounding_text()); 859 EXPECT_EQ(3U, 860 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); 861 EXPECT_EQ(3U, 862 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); 863 } 864 865 TEST_F(InputMethodChromeOSTest, SurroundingText_SelectionTest) { 866 ime_->Init(true); 867 // Click a text input form. 868 input_type_ = TEXT_INPUT_TYPE_TEXT; 869 ime_->OnTextInputTypeChanged(this); 870 871 // Set the TextInputClient behaviors. 872 surrounding_text_ = UTF8ToUTF16("abcdef"); 873 text_range_ = gfx::Range(0, 6); 874 selection_range_ = gfx::Range(2, 5); 875 876 // Set the verifier for SetSurroundingText mock call. 877 SetSurroundingTextVerifier verifier(UTF16ToUTF8(surrounding_text_), 2, 5); 878 879 ime_->OnCaretBoundsChanged(this); 880 881 // Check the call count. 882 EXPECT_EQ(1, 883 mock_ime_engine_handler_->set_surrounding_text_call_count()); 884 EXPECT_EQ(UTF16ToUTF8(surrounding_text_), 885 mock_ime_engine_handler_->last_set_surrounding_text()); 886 EXPECT_EQ(2U, 887 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); 888 EXPECT_EQ(5U, 889 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); 890 } 891 892 TEST_F(InputMethodChromeOSTest, SurroundingText_PartialText) { 893 ime_->Init(true); 894 // Click a text input form. 895 input_type_ = TEXT_INPUT_TYPE_TEXT; 896 ime_->OnTextInputTypeChanged(this); 897 898 // Set the TextInputClient behaviors. 899 surrounding_text_ = UTF8ToUTF16("abcdefghij"); 900 text_range_ = gfx::Range(5, 10); 901 selection_range_ = gfx::Range(7, 9); 902 903 ime_->OnCaretBoundsChanged(this); 904 905 // Check the call count. 906 EXPECT_EQ(1, 907 mock_ime_engine_handler_->set_surrounding_text_call_count()); 908 // Set the verifier for SetSurroundingText mock call. 909 // Here (2, 4) is selection range in expected surrounding text coordinates. 910 EXPECT_EQ("fghij", 911 mock_ime_engine_handler_->last_set_surrounding_text()); 912 EXPECT_EQ(2U, 913 mock_ime_engine_handler_->last_set_surrounding_cursor_pos()); 914 EXPECT_EQ(4U, 915 mock_ime_engine_handler_->last_set_surrounding_anchor_pos()); 916 } 917 918 TEST_F(InputMethodChromeOSTest, SurroundingText_BecomeEmptyText) { 919 ime_->Init(true); 920 // Click a text input form. 921 input_type_ = TEXT_INPUT_TYPE_TEXT; 922 ime_->OnTextInputTypeChanged(this); 923 924 // Set the TextInputClient behaviors. 925 // If the surrounding text becomes empty, text_range become (0, 0) and 926 // selection range become invalid. 927 surrounding_text_ = UTF8ToUTF16(""); 928 text_range_ = gfx::Range(0, 0); 929 selection_range_ = gfx::Range::InvalidRange(); 930 931 ime_->OnCaretBoundsChanged(this); 932 933 // Check the call count. 934 EXPECT_EQ(0, 935 mock_ime_engine_handler_->set_surrounding_text_call_count()); 936 937 // Should not be called twice with same condition. 938 ime_->OnCaretBoundsChanged(this); 939 EXPECT_EQ(0, 940 mock_ime_engine_handler_->set_surrounding_text_call_count()); 941 } 942 943 class InputMethodChromeOSKeyEventTest : public InputMethodChromeOSTest { 944 public: 945 InputMethodChromeOSKeyEventTest() {} 946 virtual ~InputMethodChromeOSKeyEventTest() {} 947 948 virtual void SetUp() OVERRIDE { 949 InputMethodChromeOSTest::SetUp(); 950 ime_->Init(true); 951 } 952 953 DISALLOW_COPY_AND_ASSIGN(InputMethodChromeOSKeyEventTest); 954 }; 955 956 TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseTest) { 957 const int kFlags = ui::EF_SHIFT_DOWN; 958 ScopedXI2Event xevent; 959 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, kFlags); 960 const ui::KeyEvent event(xevent); 961 962 // Do key event. 963 input_type_ = TEXT_INPUT_TYPE_TEXT; 964 ime_->OnTextInputTypeChanged(this); 965 ime_->DispatchKeyEvent(event); 966 967 // Check before state. 968 const ui::KeyEvent* key_event = 969 mock_ime_engine_handler_->last_processed_key_event(); 970 EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count()); 971 EXPECT_EQ(ui::VKEY_A, key_event->key_code()); 972 EXPECT_EQ("KeyA", key_event->code()); 973 EXPECT_EQ(kFlags, key_event->flags()); 974 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); 975 976 // Do callback. 977 mock_ime_engine_handler_->last_passed_callback().Run(true); 978 979 // Check the results 980 EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); 981 const ui::KeyEvent* stored_event = 982 ime_->process_key_event_post_ime_args().event; 983 EXPECT_TRUE(stored_event->HasNativeEvent()); 984 EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event()))); 985 EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); 986 } 987 988 TEST_F(InputMethodChromeOSKeyEventTest, MultiKeyEventDelayResponseTest) { 989 // Preparation 990 input_type_ = TEXT_INPUT_TYPE_TEXT; 991 ime_->OnTextInputTypeChanged(this); 992 993 const int kFlags = ui::EF_SHIFT_DOWN; 994 ScopedXI2Event xevent; 995 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_B, kFlags); 996 const ui::KeyEvent event(xevent); 997 998 // Do key event. 999 ime_->DispatchKeyEvent(event); 1000 const ui::KeyEvent* key_event = 1001 mock_ime_engine_handler_->last_processed_key_event(); 1002 EXPECT_EQ(ui::VKEY_B, key_event->key_code()); 1003 EXPECT_EQ("KeyB", key_event->code()); 1004 EXPECT_EQ(kFlags, key_event->flags()); 1005 1006 KeyEventCallback first_callback = 1007 mock_ime_engine_handler_->last_passed_callback(); 1008 1009 // Do key event again. 1010 ScopedXI2Event xevent2; 1011 xevent2.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_C, kFlags); 1012 const ui::KeyEvent event2(xevent2); 1013 1014 ime_->DispatchKeyEvent(event2); 1015 const ui::KeyEvent* key_event2 = 1016 mock_ime_engine_handler_->last_processed_key_event(); 1017 EXPECT_EQ(ui::VKEY_C, key_event2->key_code()); 1018 EXPECT_EQ("KeyC", key_event2->code()); 1019 EXPECT_EQ(kFlags, key_event2->flags()); 1020 1021 // Check before state. 1022 EXPECT_EQ(2, 1023 mock_ime_engine_handler_->process_key_event_call_count()); 1024 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); 1025 1026 // Do callback for first key event. 1027 first_callback.Run(true); 1028 1029 // Check the results for first key event. 1030 EXPECT_EQ(1, ime_->process_key_event_post_ime_call_count()); 1031 const ui::KeyEvent* stored_event = 1032 ime_->process_key_event_post_ime_args().event; 1033 EXPECT_TRUE(stored_event->HasNativeEvent()); 1034 EXPECT_TRUE(IsEqualXKeyEvent(*xevent, *(stored_event->native_event()))); 1035 EXPECT_TRUE(ime_->process_key_event_post_ime_args().handled); 1036 1037 // Do callback for second key event. 1038 mock_ime_engine_handler_->last_passed_callback().Run(false); 1039 1040 // Check the results for second key event. 1041 EXPECT_EQ(2, ime_->process_key_event_post_ime_call_count()); 1042 stored_event = ime_->process_key_event_post_ime_args().event; 1043 EXPECT_TRUE(stored_event->HasNativeEvent()); 1044 EXPECT_TRUE(IsEqualXKeyEvent(*xevent2, *(stored_event->native_event()))); 1045 EXPECT_FALSE(ime_->process_key_event_post_ime_args().handled); 1046 } 1047 1048 TEST_F(InputMethodChromeOSKeyEventTest, KeyEventDelayResponseResetTest) { 1049 ScopedXI2Event xevent; 1050 xevent.InitKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_SHIFT_DOWN); 1051 const ui::KeyEvent event(xevent); 1052 1053 // Do key event. 1054 input_type_ = TEXT_INPUT_TYPE_TEXT; 1055 ime_->OnTextInputTypeChanged(this); 1056 ime_->DispatchKeyEvent(event); 1057 1058 // Check before state. 1059 EXPECT_EQ(1, mock_ime_engine_handler_->process_key_event_call_count()); 1060 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); 1061 1062 ime_->ResetContext(); 1063 1064 // Do callback. 1065 mock_ime_engine_handler_->last_passed_callback().Run(true); 1066 1067 EXPECT_EQ(0, ime_->process_key_event_post_ime_call_count()); 1068 } 1069 // TODO(nona): Introduce ProcessKeyEventPostIME tests(crbug.com/156593). 1070 1071 } // namespace ui 1072