Home | History | Annotate | Download | only in ime
      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