15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/base/ime/input_method_chromeos.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cstring> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/char_iterator.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 165e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/sys_info.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/icu/icu_utf.h" 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chromeos/ime/composition_text.h" 21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chromeos/ime/ime_keyboard.h" 22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chromeos/ime/input_method_manager.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/ime/text_input_client.h" 24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)chromeos::IMEEngineHandlerInterface* GetEngine() { 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return chromeos::IMEBridge::Get()->GetCurrentEngineHandler(); 3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ui { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// InputMethodChromeOS implementation ----------------------------------------- 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)InputMethodChromeOS::InputMethodChromeOS( 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) internal::InputMethodDelegate* delegate) 38c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch : composing_text_(false), 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_(false), 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_keyevent_id_(0), 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_(this) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetDelegate(delegate); 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::IMEBridge::Get()->SetInputContextHandler(this); 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) UpdateContextFocusState(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)InputMethodChromeOS::~InputMethodChromeOS() { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AbandonAllPendingKeyEvents(); 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ConfirmCompositionText(); 5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // We are dead, so we need to ask the client to stop relying on us. 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) OnInputMethodChanged(); 5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::IMEBridge::Get()->SetInputContextHandler(NULL); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnFocus() { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InputMethodBase::OnFocus(); 59c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch OnTextInputTypeChanged(GetTextInputClient()); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnBlur() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConfirmCompositionText(); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InputMethodBase::OnBlur(); 65c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch OnTextInputTypeChanged(GetTextInputClient()); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::OnUntranslatedIMEMessage( 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::NativeEvent& event, 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NativeEventResult* result) { 717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) return false; 727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)} 737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ProcessKeyEventDone(uint32 id, 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ui::KeyEvent* event, 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool is_handled) { 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (pending_key_events_.find(id) == pending_key_events_.end()) 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; // Abandoned key event. 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(event); 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ET_KEY_PRESSED) { 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (is_handled) { 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // IME event has a priority to be handled, so that character composer 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // should be reset. 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) character_composer_.Reset(); 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If IME does not handle key event, passes keyevent to character composer 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // to be able to compose complex characters. 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) is_handled = ExecuteCharacterComposer(*event); 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event->type() == ET_KEY_PRESSED || event->type() == ET_KEY_RELEASED) 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessKeyEventPostIME(*event, is_handled); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // ProcessKeyEventPostIME may change the |pending_key_events_|. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_key_events_.erase(id); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::DispatchKeyEvent(const ui::KeyEvent& event) { 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(event.type() == ET_KEY_PRESSED || event.type() == ET_KEY_RELEASED); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(system_toplevel_window_focused()); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // For linux_chromeos, the ime keyboard cannot track the caps lock state by 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // itself, so need to call SetCapsLockEnabled() method to reflect the caps 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // lock state by the key event. 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!base::SysInfo::IsRunningOnChromeOS()) { 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chromeos::input_method::InputMethodManager* manager = 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chromeos::input_method::InputMethodManager::Get(); 110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (manager) { 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) chromeos::input_method::ImeKeyboard* keyboard = manager->GetImeKeyboard(); 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (keyboard && event.type() == ui::ET_KEY_PRESSED) { 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) bool caps = (event.key_code() == ui::VKEY_CAPITAL) 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ? !keyboard->CapsLockIsEnabled() 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : (event.flags() & EF_CAPS_LOCK_DOWN); 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) keyboard->SetCapsLockEnabled(caps); 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If |context_| is not usable, then we can only dispatch the key event as is. 122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // We only dispatch the key event to input method when the |context_| is an 123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // normal input field (not a password field). 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: We need to send the key event to ibus even if the |context_| is not 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // enabled, so that ibus can have a chance to enable the |context_|. 126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!IsInputFieldFocused() || !GetEngine()) { 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event.type() == ET_KEY_PRESSED) { 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (ExecuteCharacterComposer(event)) { 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Treating as PostIME event if character composer handles key event and 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // generates some IME event, 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessKeyEventPostIME(event, true); 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessUnfilteredKeyPressEvent(event); 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(event); 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_key_events_.insert(current_keyevent_id_); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ui::KeyEvent* copied_event = new ui::KeyEvent(event); 14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetEngine()->ProcessKeyEvent( 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event, 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&InputMethodChromeOS::ProcessKeyEventDone, 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_keyevent_id_, 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Pass the ownership of |copied_event|. 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::Owned(copied_event))); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current_keyevent_id_; 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnTextInputTypeChanged( 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const TextInputClient* client) { 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!IsTextInputClientFocused(client)) 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) UpdateContextFocusState(); 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) chromeos::IMEEngineHandlerInterface* engine = GetEngine(); 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (engine) { 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // When focused input client is not changed, a text input type change should 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // cause blur/focus events to engine. 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The focus in to or out from password field should also notify engine. 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) engine->FocusOut(); 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) chromeos::IMEEngineHandlerInterface::InputContext context( 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetTextInputType(), GetTextInputMode()); 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) engine->FocusIn(context); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) InputMethodBase::OnTextInputTypeChanged(client); 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnCaretBoundsChanged(const TextInputClient* client) { 178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!IsInputFieldFocused() || !IsTextInputClientFocused(client)) 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The current text input type should not be NONE if |context_| is focused. 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(!IsTextInputTypeNone()); 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::Rect rect = GetTextInputClient()->GetCaretBounds(); 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Rect composition_head; 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!GetTextInputClient()->GetCompositionCharacterBounds(0, 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &composition_head)) { 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) composition_head = rect; 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeos::IMECandidateWindowHandlerInterface* candidate_window = 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::IMEBridge::Get()->GetCandidateWindowHandler(); 193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!candidate_window) 194f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 195f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) candidate_window->SetCursorBounds(rect, composition_head); 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 197f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Range text_range; 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) gfx::Range selection_range; 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 surrounding_text; 200f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!GetTextInputClient()->GetTextRange(&text_range) || 201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !GetTextInputClient()->GetTextFromRange(text_range, &surrounding_text) || 202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) !GetTextInputClient()->GetSelectionRange(&selection_range)) { 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) previous_surrounding_text_.clear(); 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) previous_selection_range_ = gfx::Range::InvalidRange(); 205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (previous_selection_range_ == selection_range && 209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) previous_surrounding_text_ == surrounding_text) 210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) previous_selection_range_ = selection_range; 213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) previous_surrounding_text_ = surrounding_text; 214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!selection_range.IsValid()) { 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(nona): Ideally selection_range should not be invalid. 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // TODO(nona): If javascript changes the focus on page loading, even (0,0) 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // can not be obtained. Need investigation. 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Here SetSurroundingText accepts relative position of |surrounding_text|, so 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // we have to convert |selection_range| from node coordinates to 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // |surrounding_text| coordinates. 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!GetEngine()) 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetEngine()->SetSurroundingText(base::UTF16ToUTF8(surrounding_text), 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) selection_range.start() - text_range.start(), 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) selection_range.end() - text_range.start()); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::CancelComposition(const TextInputClient* client) { 233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (IsInputFieldFocused() && IsTextInputClientFocused(client)) 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetContext(); 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnInputLocaleChanged() { 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Not supported. 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string InputMethodChromeOS::GetInputLocale() { 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not supported. 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ""; 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::IsActive() { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::IsCandidatePopupOpen() const { 251eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // TODO(yukishiino): Implement this method. 252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnWillChangeFocusedClient( 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TextInputClient* focused_before, 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TextInputClient* focused) { 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConfirmCompositionText(); 259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (GetEngine()) 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetEngine()->FocusOut(); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::OnDidChangeFocusedClient( 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TextInputClient* focused_before, 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) TextInputClient* focused) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Force to update the input type since client's TextInputStateChanged() 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // function might not be called if text input types before the client loses 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // focus and after it acquires focus again are the same. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateContextFocusState(); 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (GetEngine()) { 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) chromeos::IMEEngineHandlerInterface::InputContext context( 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetTextInputType(), GetTextInputMode()); 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GetEngine()->FocusIn(context); 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ConfirmCompositionText() { 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextInputClient* client = GetTextInputClient(); 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client && client->HasCompositionText()) 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->ConfirmCompositionText(); 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetContext(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ResetContext() { 288c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (!IsInputFieldFocused() || !GetTextInputClient()) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(system_toplevel_window_focused()); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_.Clear(); 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_text_.clear(); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composing_text_ = false; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = false; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to abandon all pending key events, but as above comment says, there 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is no reliable way to abandon all results generated by these abandoned key 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // events. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AbandonAllPendingKeyEvents(); 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This function runs asynchronously. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: some input method engines may not support reset method, such as 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ibus-anthy. But as we control all input method engines by ourselves, we can 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // make sure that all of the engines we are using support it correctly. 30758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (GetEngine()) 30858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetEngine()->Reset(); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) character_composer_.Reset(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::UpdateContextFocusState() { 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ResetContext(); 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) OnInputMethodChanged(); 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Propagate the focus event to the candidate window handler which also 318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // manages the input method mode indicator. 319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeos::IMECandidateWindowHandlerInterface* candidate_window = 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::IMEBridge::Get()->GetCandidateWindowHandler(); 321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (candidate_window) 322c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch candidate_window->FocusStateChanged(IsInputFieldFocused()); 323f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) chromeos::IMEBridge::Get()->SetCurrentTextInputType(GetTextInputType()); 3250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!IsTextInputTypeNone()) 32758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) OnCaretBoundsChanged(GetTextInputClient()); 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ProcessKeyEventPostIME( 331f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const ui::KeyEvent& event, 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled) { 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextInputClient* client = GetTextInputClient(); 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!client) { 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // As ibus works asynchronously, there is a chance that the focused client 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loses focus before this method gets called. 337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(event); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event.type() == ET_KEY_PRESSED && handled) 342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessFilteredKeyPressEvent(event); 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In case the focus was changed by the key event. The |context_| should have 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // been reset when the focused window changed. 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client != GetTextInputClient()) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HasInputMethodResult()) 350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessInputMethodResult(event, handled); 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In case the focus was changed when sending input method results to the 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // focused window. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client != GetTextInputClient()) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (event.type() == ET_KEY_PRESSED && !handled) 358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ProcessUnfilteredKeyPressEvent(event); 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) else if (event.type() == ET_KEY_RELEASED) 360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(event); 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ProcessFilteredKeyPressEvent( 3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const ui::KeyEvent& event) { 365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (NeedInsertChar()) { 366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(event); 367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else { 368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const ui::KeyEvent fabricated_event(ET_KEY_PRESSED, 369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) VKEY_PROCESSKEY, 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) event.flags(), 371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) false); // is_char 372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(fabricated_event); 373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ProcessUnfilteredKeyPressEvent( 377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const ui::KeyEvent& event) { 378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const TextInputClient* prev_client = GetTextInputClient(); 379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DispatchKeyEventPostIME(event); 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We shouldn't dispatch the character anymore if the key event dispatch 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // caused focus change. For example, in the following scenario, 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. visit a web page which has a <textarea>. 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. click Omnibox. 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3. enable Korean IME, press A, then press Tab to move the focus to the web 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // page. 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should return here not to send the Tab key event to RWHV. 388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TextInputClient* client = GetTextInputClient(); 389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!client || client != prev_client) 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a key event was not filtered by |context_| and |character_composer_|, 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then it means the key event didn't generate any result text. So we need 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to send corresponding character to the focused text input client. 395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint16 ch = event.GetCharacter(); 396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (ch) 397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) client->InsertChar(ch, event.flags()); 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ProcessInputMethodResult(const ui::KeyEvent& event, 401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool handled) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextInputClient* client = GetTextInputClient(); 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(client); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result_text_.length()) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (handled && NeedInsertChar()) { 4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (base::string16::const_iterator i = result_text_.begin(); 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) i != result_text_.end(); ++i) { 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) client->InsertChar(*i, event.flags()); 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->InsertText(result_text_); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composing_text_ = false; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (composition_changed_ && !IsTextInputTypeNone()) { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (composition_.text.length()) { 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composing_text_ = true; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->SetCompositionText(composition_); 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (result_text_.empty()) { 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->ClearCompositionText(); 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should not clear composition text here, as it may belong to the next 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // composition session. 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_text_.clear(); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = false; 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::NeedInsertChar() const { 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetTextInputClient() && 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (IsTextInputTypeNone() || 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!composing_text_ && result_text_.length() == 1)); 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::HasInputMethodResult() const { 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result_text_.length() || composition_changed_; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 44246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void InputMethodChromeOS::SendFakeProcessKeyEvent(bool pressed) const { 44346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!GetTextInputClient()) 44446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 44546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) KeyEvent evt(pressed ? ET_KEY_PRESSED : ET_KEY_RELEASED, 44646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) pressed ? VKEY_PROCESSKEY : VKEY_UNKNOWN, 44746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) EF_IME_FABRICATED_KEY, 44846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) false); // is_char 44946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) DispatchKeyEventPostIME(evt); 45046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} 45146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::AbandonAllPendingKeyEvents() { 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_key_events_.clear(); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::CommitText(const std::string& text) { 4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (text.empty()) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We need to receive input method result even if the text input type is 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TEXT_INPUT_TYPE_NONE, to make sure we can always send correct 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // character for each key event to the focused text input client. 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetTextInputClient()) 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::string16 utf16_text = base::UTF8ToUTF16(text); 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (utf16_text.empty()) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append the text to the buffer, because commit signal might be fired 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // multiple times when processing a key event. 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_text_.append(utf16_text); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we are not handling key event, do not bother sending text result if the 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // focused text input client does not support text input. 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_key_events_.empty() && !IsTextInputTypeNone()) { 47746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(true); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetTextInputClient()->InsertText(utf16_text); 47946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(false); 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result_text_.clear(); 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::UpdateCompositionText( 4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const chromeos::CompositionText& text, 4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 cursor_pos, 4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool visible) { 4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (IsTextInputTypeNone()) 4894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 4904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 49158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!CanComposeInline()) { 492a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) chromeos::IMECandidateWindowHandlerInterface* candidate_window = 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::IMEBridge::Get()->GetCandidateWindowHandler(); 49458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (candidate_window) 49558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) candidate_window->UpdatePreeditText(text.text(), cursor_pos, visible); 49658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 49758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |visible| argument is very confusing. For example, what's the correct 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // behavior when: 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1. OnUpdatePreeditText() is called with a text and visible == false, then 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2. OnShowPreeditText() is called afterwards. 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it's only for clearing the current preedit text, then why not just use 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OnHidePreeditText()? 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!visible) { 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HidePreeditText(); 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtractCompositionText(text, cursor_pos, &composition_); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = true; 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In case OnShowPreeditText() is not called. 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (composition_.text.length()) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composing_text_ = true; 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we receive a composition text without pending key event, then we need to 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // send it to the focused text input client directly. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_key_events_.empty()) { 52146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(true); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetTextInputClient()->SetCompositionText(composition_); 52346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(false); 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = false; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_.Clear(); 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::HidePreeditText() { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (composition_.text.empty() || IsTextInputTypeNone()) 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Intentionally leaves |composing_text_| unchanged. 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = true; 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_.Clear(); 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pending_key_events_.empty()) { 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TextInputClient* client = GetTextInputClient(); 53946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (client && client->HasCompositionText()) { 54046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(true); 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client->ClearCompositionText(); 54246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) SendFakeProcessKeyEvent(false); 54346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) composition_changed_ = false; 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::DeleteSurroundingText(int32 offset, uint32 length) { 549b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (!composition_.text.empty()) 550b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; // do nothing if there is ongoing composition. 551b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (offset < 0 && static_cast<uint32>(-1 * offset) != length) 552b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return; // only preceding text can be deletable. 553b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (GetTextInputClient()) 554b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) GetTextInputClient()->ExtendSelectionAndDelete(length, 0U); 555b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)} 556b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InputMethodChromeOS::ExecuteCharacterComposer(const ui::KeyEvent& event) { 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!character_composer_.FilterKeyPress(event)) 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 5607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // CharacterComposer consumed the key event. Update the composition text. 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::CompositionText preedit; 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) preedit.set_text(character_composer_.preedit_string()); 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UpdateCompositionText(preedit, preedit.text().size(), 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !preedit.text().empty()); 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string commit_text = 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::UTF16ToUTF8(character_composer_.composed_character()); 568868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!commit_text.empty()) { 5694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) CommitText(commit_text); 570868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 572868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 573868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void InputMethodChromeOS::ExtractCompositionText( 5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const chromeos::CompositionText& text, 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 cursor_position, 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CompositionText* out_composition) const { 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_composition->Clear(); 5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) out_composition->text = text.text(); 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out_composition->text.empty()) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ibus uses character index for cursor position and attribute range, but we 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use char16 offset for them. So we need to do conversion here. 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::vector<size_t> char16_offsets; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length = out_composition->text.length(); 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::i18n::UTF16CharIterator char_iterator(&out_composition->text); 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char16_offsets.push_back(char_iterator.array_pos()); 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (char_iterator.Advance()); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The text length in Unicode characters. 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint32 char_length = static_cast<uint32>(char16_offsets.size()); 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure we can convert the value of |char_length| as well. 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char16_offsets.push_back(length); 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t cursor_offset = 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char16_offsets[std::min(char_length, cursor_position)]; 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 60158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) out_composition->selection = gfx::Range(cursor_offset); 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::vector<chromeos::CompositionText::UnderlineAttribute>& 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) underline_attributes = text.underline_attributes(); 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!underline_attributes.empty()) { 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < underline_attributes.size(); ++i) { 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32 start = underline_attributes[i].start_index; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const uint32 end = underline_attributes[i].end_index; 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (start >= end) 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CompositionUnderline underline(char16_offsets[start], 6126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) char16_offsets[end], 6136d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SK_ColorBLACK, 6146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) false /* thick */, 6156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SK_ColorTRANSPARENT); 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (underline_attributes[i].type == 6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_DOUBLE) 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) underline.thick = true; 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (underline_attributes[i].type == 6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) chromeos::CompositionText::COMPOSITION_TEXT_UNDERLINE_ERROR) 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) underline.color = SK_ColorRED; 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_composition->underlines.push_back(underline); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 626a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DCHECK(text.selection_start() <= text.selection_end()); 627a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (text.selection_start() < text.selection_end()) { 628a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const uint32 start = text.selection_start(); 629a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const uint32 end = text.selection_end(); 6306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) CompositionUnderline underline(char16_offsets[start], 6316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) char16_offsets[end], 6326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SK_ColorBLACK, 6336d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) true /* thick */, 6346d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) SK_ColorTRANSPARENT); 635a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) out_composition->underlines.push_back(underline); 636a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 637a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // If the cursor is at start or end of this underline, then we treat 638a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // it as the selection range as well, but make sure to set the cursor 639a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // position to the selection end. 640a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (underline.start_offset == cursor_offset) { 641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) out_composition->selection.set_start(underline.end_offset); 642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) out_composition->selection.set_end(cursor_offset); 643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } else if (underline.end_offset == cursor_offset) { 644a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) out_composition->selection.set_start(underline.start_offset); 645a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) out_composition->selection.set_end(cursor_offset); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use a black thin underline by default. 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (out_composition->underlines.empty()) { 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) out_composition->underlines.push_back(CompositionUnderline( 6526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 0, length, SK_ColorBLACK, false /* thick */, SK_ColorTRANSPARENT)); 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 656c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool InputMethodChromeOS::IsInputFieldFocused() { 657c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch TextInputType type = GetTextInputType(); 658c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return (type != TEXT_INPUT_TYPE_NONE) && (type != TEXT_INPUT_TYPE_PASSWORD); 659c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 660c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ui 662