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