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 : 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_EQ(base::MessageLoop::TYPE_UI, base::MessageLoop::current()->type()); 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