1 // Copyright (c) 2012 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/views/ime/input_method_bridge.h" 6 7 #include "ui/base/ime/input_method.h" 8 #include "ui/base/ime/input_method_observer.h" 9 #include "ui/events/event.h" 10 #include "ui/gfx/rect.h" 11 #include "ui/views/view.h" 12 #include "ui/views/widget/widget.h" 13 14 namespace views { 15 16 // InputMethodBridge::HostObserver class --------------------------------------- 17 18 // An observer class for observing the host input method. When the host input 19 // method is destroyed, it will null out the |host_| field on the 20 // InputMethodBridge object. 21 class InputMethodBridge::HostObserver : public ui::InputMethodObserver { 22 public: 23 explicit HostObserver(InputMethodBridge* bridge); 24 virtual ~HostObserver(); 25 26 virtual void OnTextInputTypeChanged( 27 const ui::TextInputClient* client) OVERRIDE {} 28 virtual void OnFocus() OVERRIDE {} 29 virtual void OnBlur() OVERRIDE {} 30 virtual void OnCaretBoundsChanged( 31 const ui::TextInputClient* client) OVERRIDE {} 32 virtual void OnTextInputStateChanged( 33 const ui::TextInputClient* client) OVERRIDE {} 34 virtual void OnInputMethodDestroyed( 35 const ui::InputMethod* input_method) OVERRIDE; 36 virtual void OnShowImeIfNeeded() OVERRIDE {} 37 38 private: 39 InputMethodBridge* bridge_; 40 41 DISALLOW_COPY_AND_ASSIGN(HostObserver); 42 }; 43 44 InputMethodBridge::HostObserver::HostObserver(InputMethodBridge* bridge) 45 : bridge_(bridge) { 46 bridge_->host_->AddObserver(this); 47 } 48 49 InputMethodBridge::HostObserver::~HostObserver() { 50 if (bridge_->host_) 51 bridge_->host_->RemoveObserver(this); 52 } 53 54 void InputMethodBridge::HostObserver::OnInputMethodDestroyed( 55 const ui::InputMethod* input_method) { 56 DCHECK_EQ(bridge_->host_, input_method); 57 bridge_->host_->RemoveObserver(this); 58 bridge_->host_ = NULL; 59 } 60 61 // InputMethodBridge class ----------------------------------------------------- 62 63 InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate* delegate, 64 ui::InputMethod* host, 65 bool shared_input_method) 66 : host_(host), 67 shared_input_method_(shared_input_method) { 68 DCHECK(host_); 69 SetDelegate(delegate); 70 71 host_observer_.reset(new HostObserver(this)); 72 } 73 74 InputMethodBridge::~InputMethodBridge() { 75 // By the time we get here it's very likely |widget_|'s NativeWidget has been 76 // destroyed. This means any calls to |widget_| that go to the NativeWidget, 77 // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to 78 // this and go into |widget_|. NULL out |widget_| so we don't attempt to use 79 // it. 80 DetachFromWidget(); 81 82 // Host input method might have been destroyed at this point. 83 if (host_) 84 host_->DetachTextInputClient(this); 85 } 86 87 void InputMethodBridge::OnFocus() { 88 DCHECK(host_); 89 90 // Direct the shared IME to send TextInputClient messages to |this| object. 91 if (shared_input_method_ || !host_->GetTextInputClient()) 92 host_->SetFocusedTextInputClient(this); 93 94 // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move 95 // text input type tracker code to ui::InputMethodBase. 96 if (GetFocusedView()) { 97 OnTextInputTypeChanged(GetFocusedView()); 98 OnCaretBoundsChanged(GetFocusedView()); 99 } 100 } 101 102 void InputMethodBridge::OnBlur() { 103 DCHECK(host_); 104 105 if (HasCompositionText()) { 106 ConfirmCompositionText(); 107 host_->CancelComposition(this); 108 } 109 110 if (host_->GetTextInputClient() == this) 111 host_->SetFocusedTextInputClient(NULL); 112 } 113 114 bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent& event, 115 NativeEventResult* result) { 116 DCHECK(host_); 117 118 return host_->OnUntranslatedIMEMessage(event, result); 119 } 120 121 void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent& key) { 122 DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED); 123 124 // We can just dispatch the event here since the |key| is already processed by 125 // the system-wide IME. 126 DispatchKeyEventPostIME(key); 127 } 128 129 void InputMethodBridge::OnTextInputTypeChanged(View* view) { 130 DCHECK(host_); 131 132 if (IsViewFocused(view)) 133 host_->OnTextInputTypeChanged(this); 134 InputMethodBase::OnTextInputTypeChanged(view); 135 } 136 137 void InputMethodBridge::OnCaretBoundsChanged(View* view) { 138 DCHECK(host_); 139 140 if (IsViewFocused(view) && !IsTextInputTypeNone()) 141 host_->OnCaretBoundsChanged(this); 142 } 143 144 void InputMethodBridge::CancelComposition(View* view) { 145 DCHECK(host_); 146 147 if (IsViewFocused(view)) 148 host_->CancelComposition(this); 149 } 150 151 void InputMethodBridge::OnInputLocaleChanged() { 152 DCHECK(host_); 153 154 host_->OnInputLocaleChanged(); 155 } 156 157 std::string InputMethodBridge::GetInputLocale() { 158 DCHECK(host_); 159 160 return host_->GetInputLocale(); 161 } 162 163 bool InputMethodBridge::IsActive() { 164 DCHECK(host_); 165 166 return host_->IsActive(); 167 } 168 169 bool InputMethodBridge::IsCandidatePopupOpen() const { 170 DCHECK(host_); 171 172 return host_->IsCandidatePopupOpen(); 173 } 174 175 void InputMethodBridge::ShowImeIfNeeded() { 176 DCHECK(host_); 177 host_->ShowImeIfNeeded(); 178 } 179 180 // Overridden from TextInputClient. Forward an event from the system-wide IME 181 // to the text input |client|, which is e.g. views::Textfield. 182 void InputMethodBridge::SetCompositionText( 183 const ui::CompositionText& composition) { 184 TextInputClient* client = GetTextInputClient(); 185 if (client) 186 client->SetCompositionText(composition); 187 } 188 189 void InputMethodBridge::ConfirmCompositionText() { 190 TextInputClient* client = GetTextInputClient(); 191 if (client) 192 client->ConfirmCompositionText(); 193 } 194 195 void InputMethodBridge::ClearCompositionText() { 196 TextInputClient* client = GetTextInputClient(); 197 if (client) 198 client->ClearCompositionText(); 199 } 200 201 void InputMethodBridge::InsertText(const base::string16& text) { 202 TextInputClient* client = GetTextInputClient(); 203 if (client) 204 client->InsertText(text); 205 } 206 207 void InputMethodBridge::InsertChar(base::char16 ch, int flags) { 208 TextInputClient* client = GetTextInputClient(); 209 if (client) 210 client->InsertChar(ch, flags); 211 } 212 213 gfx::NativeWindow InputMethodBridge::GetAttachedWindow() const { 214 TextInputClient* client = GetTextInputClient(); 215 return client ? 216 client->GetAttachedWindow() : static_cast<gfx::NativeWindow>(NULL); 217 } 218 219 ui::TextInputType InputMethodBridge::GetTextInputType() const { 220 TextInputClient* client = GetTextInputClient(); 221 return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE; 222 } 223 224 ui::TextInputMode InputMethodBridge::GetTextInputMode() const { 225 TextInputClient* client = GetTextInputClient(); 226 return client ? client->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT; 227 } 228 229 bool InputMethodBridge::CanComposeInline() const { 230 TextInputClient* client = GetTextInputClient(); 231 return client ? client->CanComposeInline() : true; 232 } 233 234 gfx::Rect InputMethodBridge::GetCaretBounds() const { 235 TextInputClient* client = GetTextInputClient(); 236 if (!client) 237 return gfx::Rect(); 238 239 return client->GetCaretBounds(); 240 } 241 242 bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index, 243 gfx::Rect* rect) const { 244 DCHECK(rect); 245 TextInputClient* client = GetTextInputClient(); 246 if (!client) 247 return false; 248 249 return client->GetCompositionCharacterBounds(index, rect); 250 } 251 252 bool InputMethodBridge::HasCompositionText() const { 253 TextInputClient* client = GetTextInputClient(); 254 return client ? client->HasCompositionText() : false; 255 } 256 257 bool InputMethodBridge::GetTextRange(gfx::Range* range) const { 258 TextInputClient* client = GetTextInputClient(); 259 return client ? client->GetTextRange(range) : false; 260 } 261 262 bool InputMethodBridge::GetCompositionTextRange(gfx::Range* range) const { 263 TextInputClient* client = GetTextInputClient(); 264 return client ? client->GetCompositionTextRange(range) : false; 265 } 266 267 bool InputMethodBridge::GetSelectionRange(gfx::Range* range) const { 268 TextInputClient* client = GetTextInputClient(); 269 return client ? client->GetSelectionRange(range) : false; 270 } 271 272 bool InputMethodBridge::SetSelectionRange(const gfx::Range& range) { 273 TextInputClient* client = GetTextInputClient(); 274 return client ? client->SetSelectionRange(range) : false; 275 } 276 277 bool InputMethodBridge::DeleteRange(const gfx::Range& range) { 278 TextInputClient* client = GetTextInputClient(); 279 return client ? client->DeleteRange(range) : false; 280 } 281 282 bool InputMethodBridge::GetTextFromRange(const gfx::Range& range, 283 base::string16* text) const { 284 TextInputClient* client = GetTextInputClient(); 285 return client ? client->GetTextFromRange(range, text) : false; 286 } 287 288 void InputMethodBridge::OnInputMethodChanged() { 289 TextInputClient* client = GetTextInputClient(); 290 if (client) 291 client->OnInputMethodChanged(); 292 } 293 294 bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment( 295 base::i18n::TextDirection direction) { 296 TextInputClient* client = GetTextInputClient(); 297 return client ? 298 client->ChangeTextDirectionAndLayoutAlignment(direction) : false; 299 } 300 301 void InputMethodBridge::ExtendSelectionAndDelete(size_t before, size_t after) { 302 TextInputClient* client = GetTextInputClient(); 303 if (client) 304 client->ExtendSelectionAndDelete(before, after); 305 } 306 307 void InputMethodBridge::EnsureCaretInRect(const gfx::Rect& rect) { 308 TextInputClient* client = GetTextInputClient(); 309 if (client) 310 client->EnsureCaretInRect(rect); 311 } 312 313 void InputMethodBridge::OnCandidateWindowShown() { 314 } 315 316 void InputMethodBridge::OnCandidateWindowUpdated() { 317 } 318 319 void InputMethodBridge::OnCandidateWindowHidden() { 320 } 321 322 bool InputMethodBridge::IsEditingCommandEnabled(int command_id) { 323 return false; 324 } 325 326 void InputMethodBridge::ExecuteEditingCommand(int command_id) { 327 } 328 329 // Overridden from FocusChangeListener. 330 void InputMethodBridge::OnWillChangeFocus(View* focused_before, View* focused) { 331 if (HasCompositionText()) { 332 ConfirmCompositionText(); 333 CancelComposition(focused_before); 334 } 335 } 336 337 void InputMethodBridge::OnDidChangeFocus(View* focused_before, View* focused) { 338 DCHECK_EQ(GetFocusedView(), focused); 339 OnTextInputTypeChanged(focused); 340 OnCaretBoundsChanged(focused); 341 } 342 343 ui::InputMethod* InputMethodBridge::GetHostInputMethod() const { 344 return host_; 345 } 346 347 348 } // namespace views 349