Home | History | Annotate | Download | only in ime
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/base/ime/remote_input_method_win.h"
      6 
      7 #include "base/observer_list.h"
      8 #include "base/strings/utf_string_conversions.h"
      9 #include "base/win/metro.h"
     10 #include "base/win/scoped_handle.h"
     11 #include "ui/base/ime/input_method.h"
     12 #include "ui/base/ime/input_method_delegate.h"
     13 #include "ui/base/ime/input_method_observer.h"
     14 #include "ui/base/ime/remote_input_method_delegate_win.h"
     15 #include "ui/base/ime/text_input_client.h"
     16 #include "ui/base/ime/win/tsf_input_scope.h"
     17 #include "ui/events/event.h"
     18 #include "ui/events/event_utils.h"
     19 #include "ui/gfx/rect.h"
     20 
     21 namespace ui {
     22 namespace {
     23 
     24 const LANGID kFallbackLangID =
     25     MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT);
     26 
     27 InputMethod* g_public_interface_ = NULL;
     28 RemoteInputMethodPrivateWin* g_private_interface_ = NULL;
     29 
     30 void RegisterInstance(InputMethod* public_interface,
     31                       RemoteInputMethodPrivateWin* private_interface) {
     32   CHECK(g_public_interface_ == NULL)
     33       << "Only one instance is supported at the same time";
     34   CHECK(g_private_interface_ == NULL)
     35       << "Only one instance is supported at the same time";
     36   g_public_interface_ = public_interface;
     37   g_private_interface_ = private_interface;
     38 }
     39 
     40 RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) {
     41   if (g_public_interface_ != public_interface)
     42     return NULL;
     43   return g_private_interface_;
     44 }
     45 
     46 void UnregisterInstance(InputMethod* public_interface) {
     47   RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface);
     48   if (g_public_interface_ == public_interface &&
     49       g_private_interface_ == private_interface) {
     50     g_public_interface_ = NULL;
     51     g_private_interface_ = NULL;
     52   }
     53 }
     54 
     55 std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
     56   wchar_t buffer[16] = {};
     57 
     58   //|chars_written| includes NUL terminator.
     59   const int chars_written =
     60       GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
     61   if (chars_written <= 1 || arraysize(buffer) < chars_written)
     62     return std::string();
     63   std::string result;
     64   WideToUTF8(buffer, chars_written - 1, &result);
     65   return result;
     66 }
     67 
     68 std::vector<int32> GetInputScopesAsInt(TextInputType text_input_type,
     69                                        TextInputMode text_input_mode) {
     70   std::vector<int32> result;
     71   // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE.
     72   if (text_input_type == TEXT_INPUT_TYPE_NONE)
     73     return result;
     74 
     75   const std::vector<InputScope>& input_scopes =
     76       tsf_inputscope::GetInputScopes(text_input_type, text_input_mode);
     77   result.reserve(input_scopes.size());
     78   for (size_t i = 0; i < input_scopes.size(); ++i)
     79     result.push_back(static_cast<int32>(input_scopes[i]));
     80   return result;
     81 }
     82 
     83 std::vector<gfx::Rect> GetCompositionCharacterBounds(
     84     const TextInputClient* client) {
     85   if (!client)
     86     return std::vector<gfx::Rect>();
     87 
     88   if (!client->HasCompositionText()) {
     89     std::vector<gfx::Rect> caret;
     90     caret.push_back(client->GetCaretBounds());
     91     return caret;
     92   }
     93 
     94   std::vector<gfx::Rect> bounds;
     95   for (uint32 i = 0;; ++i) {
     96     gfx::Rect rect;
     97     if (!client->GetCompositionCharacterBounds(i, &rect))
     98       break;
     99     bounds.push_back(rect);
    100   }
    101   return bounds;
    102 }
    103 
    104 class RemoteInputMethodWin : public InputMethod,
    105                              public RemoteInputMethodPrivateWin {
    106  public:
    107   explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate)
    108       : delegate_(delegate),
    109         remote_delegate_(NULL),
    110         text_input_client_(NULL),
    111         is_candidate_popup_open_(false),
    112         is_ime_(false),
    113         langid_(kFallbackLangID) {
    114     RegisterInstance(this, this);
    115   }
    116 
    117   virtual ~RemoteInputMethodWin() {
    118     FOR_EACH_OBSERVER(InputMethodObserver,
    119                       observer_list_,
    120                       OnInputMethodDestroyed(this));
    121     UnregisterInstance(this);
    122   }
    123 
    124  private:
    125   // Overridden from InputMethod:
    126   virtual void SetDelegate(internal::InputMethodDelegate* delegate) OVERRIDE {
    127     delegate_ = delegate;
    128   }
    129 
    130   virtual void Init(bool focused) OVERRIDE {
    131   }
    132 
    133   virtual void OnFocus() OVERRIDE {
    134   }
    135 
    136   virtual void OnBlur() OVERRIDE {
    137   }
    138 
    139   virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
    140                                         NativeEventResult* result) OVERRIDE {
    141     return false;
    142   }
    143 
    144   virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE {
    145     std::vector<int32> prev_input_scopes;
    146     std::swap(input_scopes_, prev_input_scopes);
    147     std::vector<gfx::Rect> prev_bounds;
    148     std::swap(composition_character_bounds_, prev_bounds);
    149     if (client) {
    150       input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
    151                                           client->GetTextInputMode());
    152       composition_character_bounds_ = GetCompositionCharacterBounds(client);
    153     }
    154 
    155     const bool text_input_client_changed = text_input_client_ != client;
    156     text_input_client_ = client;
    157     if (text_input_client_changed) {
    158       FOR_EACH_OBSERVER(InputMethodObserver,
    159                         observer_list_,
    160                         OnTextInputStateChanged(client));
    161     }
    162 
    163     if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
    164                               prev_bounds == composition_character_bounds_))
    165       return;
    166     remote_delegate_->OnTextInputClientUpdated(input_scopes_,
    167                                                composition_character_bounds_);
    168   }
    169 
    170   virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE {
    171     if (text_input_client_ != client)
    172       return;
    173     SetFocusedTextInputClient(NULL);
    174   }
    175 
    176   virtual TextInputClient* GetTextInputClient() const OVERRIDE {
    177     return text_input_client_;
    178   }
    179 
    180   virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE {
    181     if (event.HasNativeEvent()) {
    182       const base::NativeEvent& native_key_event = event.native_event();
    183       if (native_key_event.message != WM_CHAR)
    184         return false;
    185       if (!text_input_client_)
    186         return false;
    187       text_input_client_->InsertChar(
    188           static_cast<char16>(native_key_event.wParam),
    189           ui::GetModifiersFromKeyState());
    190       return true;
    191     }
    192 
    193     if (event.is_char()) {
    194       if (text_input_client_) {
    195         text_input_client_->InsertChar(event.key_code(),
    196                                        ui::GetModifiersFromKeyState());
    197       }
    198       return true;
    199     }
    200     if (!delegate_)
    201       return false;
    202     return delegate_->DispatchFabricatedKeyEventPostIME(event.type(),
    203                                                         event.key_code(),
    204                                                         event.flags());
    205   }
    206 
    207   virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
    208     if (!text_input_client_ || text_input_client_ != client)
    209       return;
    210     std::vector<int32> prev_input_scopes;
    211     std::swap(input_scopes_, prev_input_scopes);
    212     input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
    213                                         client->GetTextInputMode());
    214     if (input_scopes_ != prev_input_scopes && remote_delegate_) {
    215       remote_delegate_->OnTextInputClientUpdated(
    216           input_scopes_, composition_character_bounds_);
    217     }
    218   }
    219 
    220   virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
    221     if (!text_input_client_ || text_input_client_ != client)
    222       return;
    223     std::vector<gfx::Rect> prev_rects;
    224     std::swap(composition_character_bounds_, prev_rects);
    225     composition_character_bounds_ = GetCompositionCharacterBounds(client);
    226     if (composition_character_bounds_ != prev_rects && remote_delegate_) {
    227       remote_delegate_->OnTextInputClientUpdated(
    228           input_scopes_, composition_character_bounds_);
    229     }
    230   }
    231 
    232   virtual void CancelComposition(const TextInputClient* client) OVERRIDE {
    233     if (CanSendRemoteNotification(client))
    234       remote_delegate_->CancelComposition();
    235   }
    236 
    237   virtual void OnInputLocaleChanged() OVERRIDE {
    238   }
    239 
    240   virtual std::string GetInputLocale() OVERRIDE {
    241     const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
    242     std::string language =
    243         GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
    244     if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
    245       return language;
    246     const std::string& region =
    247         GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
    248     if (region.empty())
    249       return language;
    250     return language.append(1, '-').append(region);
    251   }
    252 
    253   virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
    254     switch (PRIMARYLANGID(langid_)) {
    255       case LANG_ARABIC:
    256       case LANG_HEBREW:
    257       case LANG_PERSIAN:
    258       case LANG_SYRIAC:
    259       case LANG_UIGHUR:
    260       case LANG_URDU:
    261         return base::i18n::RIGHT_TO_LEFT;
    262       default:
    263         return base::i18n::LEFT_TO_RIGHT;
    264     }
    265   }
    266 
    267   virtual bool IsActive() OVERRIDE {
    268     return true;  // always turned on
    269   }
    270 
    271   virtual TextInputType GetTextInputType() const OVERRIDE {
    272     return text_input_client_ ? text_input_client_->GetTextInputType()
    273                               : TEXT_INPUT_TYPE_NONE;
    274   }
    275 
    276   virtual TextInputMode GetTextInputMode() const OVERRIDE {
    277     return text_input_client_ ? text_input_client_->GetTextInputMode()
    278                               : TEXT_INPUT_MODE_DEFAULT;
    279   }
    280 
    281   virtual bool CanComposeInline() const OVERRIDE {
    282     return text_input_client_ ? text_input_client_->CanComposeInline() : true;
    283   }
    284 
    285   virtual bool IsCandidatePopupOpen() const OVERRIDE {
    286     return is_candidate_popup_open_;
    287   }
    288 
    289   virtual void AddObserver(InputMethodObserver* observer) OVERRIDE {
    290     observer_list_.AddObserver(observer);
    291   }
    292 
    293   virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE {
    294     observer_list_.RemoveObserver(observer);
    295   }
    296 
    297   // Overridden from RemoteInputMethodPrivateWin:
    298   virtual void SetRemoteDelegate(
    299       internal::RemoteInputMethodDelegateWin* delegate) OVERRIDE{
    300     remote_delegate_ = delegate;
    301 
    302     // Sync initial state.
    303     if (remote_delegate_) {
    304       remote_delegate_->OnTextInputClientUpdated(
    305           input_scopes_, composition_character_bounds_);
    306     }
    307   }
    308 
    309   virtual void OnCandidatePopupChanged(bool visible) OVERRIDE {
    310     is_candidate_popup_open_ = visible;
    311   }
    312 
    313   virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) OVERRIDE {
    314     // Note: Currently |is_ime| is not utilized yet.
    315     const bool changed = (langid_ != langid);
    316     langid_ = langid;
    317     if (changed && GetTextInputClient())
    318       GetTextInputClient()->OnInputMethodChanged();
    319   }
    320 
    321   virtual void OnCompositionChanged(
    322       const CompositionText& composition_text) OVERRIDE {
    323     if (!text_input_client_)
    324       return;
    325     text_input_client_->SetCompositionText(composition_text);
    326   }
    327 
    328   virtual void OnTextCommitted(const base::string16& text) OVERRIDE {
    329     if (!text_input_client_)
    330       return;
    331     if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) {
    332       // According to the comment in text_input_client.h,
    333       // TextInputClient::InsertText should never be called when the
    334       // text input type is TEXT_INPUT_TYPE_NONE.
    335       for (size_t i = 0; i < text.size(); ++i)
    336         text_input_client_->InsertChar(text[i], 0);
    337       return;
    338     }
    339     text_input_client_->InsertText(text);
    340   }
    341 
    342   bool CanSendRemoteNotification(
    343       const TextInputClient* text_input_client) const {
    344     return text_input_client_ &&
    345            text_input_client_ == text_input_client &&
    346            remote_delegate_;
    347   }
    348 
    349   ObserverList<InputMethodObserver> observer_list_;
    350 
    351   internal::InputMethodDelegate* delegate_;
    352   internal::RemoteInputMethodDelegateWin* remote_delegate_;
    353 
    354   TextInputClient* text_input_client_;
    355   std::vector<int32> input_scopes_;
    356   std::vector<gfx::Rect> composition_character_bounds_;
    357   bool is_candidate_popup_open_;
    358   bool is_ime_;
    359   LANGID langid_;
    360 
    361   DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
    362 };
    363 
    364 }  // namespace
    365 
    366 bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) {
    367   DWORD process_id = 0;
    368   if (GetWindowThreadProcessId(widget, &process_id) == 0)
    369     return false;
    370   base::win::ScopedHandle process_handle(::OpenProcess(
    371       PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
    372   if (!process_handle.IsValid())
    373     return false;
    374   return base::win::IsProcessImmersive(process_handle.Get());
    375 }
    376 
    377 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
    378 
    379 scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
    380     internal::InputMethodDelegate* delegate) {
    381   return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate));
    382 }
    383 
    384 // static
    385 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
    386     InputMethod* input_method) {
    387   return GetPrivate(input_method);
    388 }
    389 
    390 }  // namespace ui
    391