| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |