Home | History | Annotate | Download | only in win
      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/base/ime/win/tsf_input_scope.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/logging.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/win/windows_version.h"
     13 
     14 namespace ui {
     15 namespace tsf_inputscope {
     16 namespace {
     17 
     18 void AppendNonTrivialInputScope(std::vector<InputScope>* input_scopes,
     19                                 InputScope input_scope) {
     20   DCHECK(input_scopes);
     21 
     22   if (input_scope == IS_DEFAULT)
     23     return;
     24 
     25   if (std::find(input_scopes->begin(), input_scopes->end(), input_scope) !=
     26       input_scopes->end())
     27     return;
     28 
     29   input_scopes->push_back(input_scope);
     30 }
     31 
     32 class TSFInputScope FINAL : public ITfInputScope {
     33  public:
     34   explicit TSFInputScope(const std::vector<InputScope>& input_scopes)
     35       : input_scopes_(input_scopes),
     36         ref_count_(0) {}
     37 
     38   // ITfInputScope:
     39   STDMETHOD_(ULONG, AddRef)() OVERRIDE {
     40     return InterlockedIncrement(&ref_count_);
     41   }
     42 
     43   STDMETHOD_(ULONG, Release)() OVERRIDE {
     44     const LONG count = InterlockedDecrement(&ref_count_);
     45     if (!count) {
     46       delete this;
     47       return 0;
     48     }
     49     return static_cast<ULONG>(count);
     50   }
     51 
     52   STDMETHOD(QueryInterface)(REFIID iid, void** result) OVERRIDE {
     53     if (!result)
     54       return E_INVALIDARG;
     55     if (iid == IID_IUnknown || iid == IID_ITfInputScope) {
     56       *result = static_cast<ITfInputScope*>(this);
     57     } else {
     58       *result = NULL;
     59       return E_NOINTERFACE;
     60     }
     61     AddRef();
     62     return S_OK;
     63   }
     64 
     65   STDMETHOD(GetInputScopes)(InputScope** input_scopes, UINT* count) OVERRIDE {
     66     if (!count || !input_scopes)
     67       return E_INVALIDARG;
     68     *input_scopes = static_cast<InputScope*>(CoTaskMemAlloc(
     69         sizeof(InputScope) * input_scopes_.size()));
     70     if (!input_scopes) {
     71       *count = 0;
     72       return E_OUTOFMEMORY;
     73     }
     74 
     75     for (size_t i = 0; i < input_scopes_.size(); ++i)
     76       (*input_scopes)[i] = input_scopes_[i];
     77     *count = input_scopes_.size();
     78     return S_OK;
     79   }
     80 
     81   STDMETHOD(GetPhrase)(BSTR** phrases, UINT* count) OVERRIDE {
     82     return E_NOTIMPL;
     83   }
     84 
     85   STDMETHOD(GetRegularExpression)(BSTR* regexp) OVERRIDE {
     86     return E_NOTIMPL;
     87   }
     88 
     89   STDMETHOD(GetSRGS)(BSTR* srgs) OVERRIDE {
     90     return E_NOTIMPL;
     91   }
     92 
     93   STDMETHOD(GetXML)(BSTR* xml) OVERRIDE {
     94     return E_NOTIMPL;
     95   }
     96 
     97  private:
     98   // The corresponding text input types.
     99   std::vector<InputScope> input_scopes_;
    100 
    101   // The refrence count of this instance.
    102   volatile LONG ref_count_;
    103 
    104   DISALLOW_COPY_AND_ASSIGN(TSFInputScope);
    105 };
    106 
    107 typedef HRESULT (WINAPI *SetInputScopesFunc)(HWND window_handle,
    108                                              const InputScope* input_scope_list,
    109                                              UINT num_input_scopes,
    110                                              WCHAR**, /* unused */
    111                                              UINT, /* unused */
    112                                              WCHAR*, /* unused */
    113                                              WCHAR* /* unused */);
    114 
    115 SetInputScopesFunc g_set_input_scopes = NULL;
    116 bool g_get_proc_done = false;
    117 
    118 SetInputScopesFunc GetSetInputScopes() {
    119   DCHECK(base::MessageLoopForUI::IsCurrent());
    120   // Thread safety is not required because this function is under UI thread.
    121   if (!g_get_proc_done) {
    122     g_get_proc_done = true;
    123 
    124     // For stability reasons, we do not support Windows XP.
    125     if (base::win::GetVersion() < base::win::VERSION_VISTA)
    126       return NULL;
    127 
    128     HMODULE module = NULL;
    129     if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, L"msctf.dll",
    130         &module)) {
    131       return NULL;
    132     }
    133     g_set_input_scopes = reinterpret_cast<SetInputScopesFunc>(
    134         GetProcAddress(module, "SetInputScopes"));
    135   }
    136   return g_set_input_scopes;
    137 }
    138 
    139 InputScope ConvertTextInputTypeToInputScope(TextInputType text_input_type) {
    140   // Following mapping is based in IE10 on Windows 8.
    141   switch (text_input_type) {
    142     case TEXT_INPUT_TYPE_PASSWORD:
    143       return IS_PASSWORD;
    144     case TEXT_INPUT_TYPE_SEARCH:
    145       return IS_SEARCH;
    146     case TEXT_INPUT_TYPE_EMAIL:
    147       return IS_EMAIL_SMTPEMAILADDRESS;
    148     case TEXT_INPUT_TYPE_NUMBER:
    149       return IS_NUMBER;
    150     case TEXT_INPUT_TYPE_TELEPHONE:
    151       return IS_TELEPHONE_FULLTELEPHONENUMBER;
    152     case TEXT_INPUT_TYPE_URL:
    153       return IS_URL;
    154     default:
    155       return IS_DEFAULT;
    156   }
    157 }
    158 
    159 InputScope ConvertTextInputModeToInputScope(TextInputMode text_input_mode) {
    160   switch (text_input_mode) {
    161     case TEXT_INPUT_MODE_FULL_WIDTH_LATIN:
    162       return IS_ALPHANUMERIC_FULLWIDTH;
    163     case TEXT_INPUT_MODE_KANA:
    164       return IS_HIRAGANA;
    165     case TEXT_INPUT_MODE_KATAKANA:
    166       return IS_KATAKANA_FULLWIDTH;
    167     case TEXT_INPUT_MODE_NUMERIC:
    168       return IS_NUMBER;
    169     case TEXT_INPUT_MODE_TEL:
    170       return IS_TELEPHONE_FULLTELEPHONENUMBER;
    171     case TEXT_INPUT_MODE_EMAIL:
    172       return IS_EMAIL_SMTPEMAILADDRESS;
    173     case TEXT_INPUT_MODE_URL:
    174       return IS_URL;
    175     default:
    176       return IS_DEFAULT;
    177   }
    178 }
    179 
    180 }  // namespace
    181 
    182 std::vector<InputScope> GetInputScopes(TextInputType text_input_type,
    183                                        TextInputMode text_input_mode) {
    184   std::vector<InputScope> input_scopes;
    185 
    186   AppendNonTrivialInputScope(&input_scopes,
    187                              ConvertTextInputTypeToInputScope(text_input_type));
    188   AppendNonTrivialInputScope(&input_scopes,
    189                              ConvertTextInputModeToInputScope(text_input_mode));
    190 
    191   if (input_scopes.empty())
    192     input_scopes.push_back(IS_DEFAULT);
    193 
    194   return input_scopes;
    195 }
    196 
    197 ITfInputScope* CreateInputScope(TextInputType text_input_type,
    198                                 TextInputMode text_input_mode) {
    199   return new TSFInputScope(GetInputScopes(text_input_type, text_input_mode));
    200 }
    201 
    202 void SetInputScopeForTsfUnawareWindow(
    203     HWND window_handle,
    204     TextInputType text_input_type,
    205     TextInputMode text_input_mode) {
    206   SetInputScopesFunc set_input_scopes = GetSetInputScopes();
    207   if (!set_input_scopes)
    208     return;
    209 
    210   std::vector<InputScope> input_scopes = GetInputScopes(text_input_type,
    211                                                         text_input_mode);
    212   set_input_scopes(window_handle, &input_scopes[0], input_scopes.size(), NULL,
    213                    0, NULL, NULL);
    214 }
    215 
    216 }  // namespace tsf_inputscope
    217 }  // namespace ui
    218