• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AppendNonTrivialInputScope(std::vector<InputScope> * input_scopes,InputScope input_scope)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:
TSFInputScope(const std::vector<InputScope> & input_scopes)34   explicit TSFInputScope(const std::vector<InputScope>& input_scopes)
35       : input_scopes_(input_scopes),
36         ref_count_(0) {}
37 
38   // ITfInputScope:
STDMETHOD_(ULONG,AddRef)39   STDMETHOD_(ULONG, AddRef)() OVERRIDE {
40     return InterlockedIncrement(&ref_count_);
41   }
42 
STDMETHOD_(ULONG,Release)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 
STDMETHOD(QueryInterface)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 
STDMETHOD(GetInputScopes)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 
STDMETHOD(GetPhrase)81   STDMETHOD(GetPhrase)(BSTR** phrases, UINT* count) OVERRIDE {
82     return E_NOTIMPL;
83   }
84 
STDMETHOD(GetRegularExpression)85   STDMETHOD(GetRegularExpression)(BSTR* regexp) OVERRIDE {
86     return E_NOTIMPL;
87   }
88 
STDMETHOD(GetSRGS)89   STDMETHOD(GetSRGS)(BSTR* srgs) OVERRIDE {
90     return E_NOTIMPL;
91   }
92 
STDMETHOD(GetXML)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 
GetSetInputScopes()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 
ConvertTextInputTypeToInputScope(TextInputType text_input_type)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 
ConvertTextInputModeToInputScope(TextInputMode text_input_mode)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 
GetInputScopes(TextInputType text_input_type,TextInputMode text_input_mode)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 
CreateInputScope(TextInputType text_input_type,TextInputMode text_input_mode)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 
SetInputScopeForTsfUnawareWindow(HWND window_handle,TextInputType text_input_type,TextInputMode text_input_mode)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