1 // Copyright 2013 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/remote_input_method_win.h" 6 7 #include "base/observer_list.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "base/win/metro.h" 10 #include "base/win/scoped_handle.h" 11 #include "ui/base/ime/input_method.h" 12 #include "ui/base/ime/input_method_delegate.h" 13 #include "ui/base/ime/input_method_observer.h" 14 #include "ui/base/ime/remote_input_method_delegate_win.h" 15 #include "ui/base/ime/text_input_client.h" 16 #include "ui/base/ime/win/tsf_input_scope.h" 17 #include "ui/events/event.h" 18 #include "ui/events/event_utils.h" 19 #include "ui/gfx/rect.h" 20 21 namespace ui { 22 namespace { 23 24 const LANGID kFallbackLangID = 25 MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT); 26 27 InputMethod* g_public_interface_ = NULL; 28 RemoteInputMethodPrivateWin* g_private_interface_ = NULL; 29 30 void RegisterInstance(InputMethod* public_interface, 31 RemoteInputMethodPrivateWin* private_interface) { 32 CHECK(g_public_interface_ == NULL) 33 << "Only one instance is supported at the same time"; 34 CHECK(g_private_interface_ == NULL) 35 << "Only one instance is supported at the same time"; 36 g_public_interface_ = public_interface; 37 g_private_interface_ = private_interface; 38 } 39 40 RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) { 41 if (g_public_interface_ != public_interface) 42 return NULL; 43 return g_private_interface_; 44 } 45 46 void UnregisterInstance(InputMethod* public_interface) { 47 RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface); 48 if (g_public_interface_ == public_interface && 49 g_private_interface_ == private_interface) { 50 g_public_interface_ = NULL; 51 g_private_interface_ = NULL; 52 } 53 } 54 55 std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) { 56 wchar_t buffer[16] = {}; 57 58 //|chars_written| includes NUL terminator. 59 const int chars_written = 60 GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer)); 61 if (chars_written <= 1 || arraysize(buffer) < chars_written) 62 return std::string(); 63 std::string result; 64 WideToUTF8(buffer, chars_written - 1, &result); 65 return result; 66 } 67 68 std::vector<int32> GetInputScopesAsInt(TextInputType text_input_type, 69 TextInputMode text_input_mode) { 70 std::vector<int32> result; 71 // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE. 72 if (text_input_type == TEXT_INPUT_TYPE_NONE) 73 return result; 74 75 const std::vector<InputScope>& input_scopes = 76 tsf_inputscope::GetInputScopes(text_input_type, text_input_mode); 77 result.reserve(input_scopes.size()); 78 for (size_t i = 0; i < input_scopes.size(); ++i) 79 result.push_back(static_cast<int32>(input_scopes[i])); 80 return result; 81 } 82 83 std::vector<gfx::Rect> GetCompositionCharacterBounds( 84 const TextInputClient* client) { 85 if (!client) 86 return std::vector<gfx::Rect>(); 87 88 if (!client->HasCompositionText()) { 89 std::vector<gfx::Rect> caret; 90 caret.push_back(client->GetCaretBounds()); 91 return caret; 92 } 93 94 std::vector<gfx::Rect> bounds; 95 for (uint32 i = 0;; ++i) { 96 gfx::Rect rect; 97 if (!client->GetCompositionCharacterBounds(i, &rect)) 98 break; 99 bounds.push_back(rect); 100 } 101 return bounds; 102 } 103 104 class RemoteInputMethodWin : public InputMethod, 105 public RemoteInputMethodPrivateWin { 106 public: 107 explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate) 108 : delegate_(delegate), 109 remote_delegate_(NULL), 110 text_input_client_(NULL), 111 is_candidate_popup_open_(false), 112 is_ime_(false), 113 langid_(kFallbackLangID) { 114 RegisterInstance(this, this); 115 } 116 117 virtual ~RemoteInputMethodWin() { 118 FOR_EACH_OBSERVER(InputMethodObserver, 119 observer_list_, 120 OnInputMethodDestroyed(this)); 121 UnregisterInstance(this); 122 } 123 124 private: 125 // Overridden from InputMethod: 126 virtual void SetDelegate(internal::InputMethodDelegate* delegate) OVERRIDE { 127 delegate_ = delegate; 128 } 129 130 virtual void Init(bool focused) OVERRIDE { 131 } 132 133 virtual void OnFocus() OVERRIDE { 134 } 135 136 virtual void OnBlur() OVERRIDE { 137 } 138 139 virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event, 140 NativeEventResult* result) OVERRIDE { 141 return false; 142 } 143 144 virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE { 145 std::vector<int32> prev_input_scopes; 146 std::swap(input_scopes_, prev_input_scopes); 147 std::vector<gfx::Rect> prev_bounds; 148 std::swap(composition_character_bounds_, prev_bounds); 149 if (client) { 150 input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(), 151 client->GetTextInputMode()); 152 composition_character_bounds_ = GetCompositionCharacterBounds(client); 153 } 154 155 const bool text_input_client_changed = text_input_client_ != client; 156 text_input_client_ = client; 157 if (text_input_client_changed) { 158 FOR_EACH_OBSERVER(InputMethodObserver, 159 observer_list_, 160 OnTextInputStateChanged(client)); 161 } 162 163 if (!remote_delegate_ || (prev_input_scopes == input_scopes_ && 164 prev_bounds == composition_character_bounds_)) 165 return; 166 remote_delegate_->OnTextInputClientUpdated(input_scopes_, 167 composition_character_bounds_); 168 } 169 170 virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE { 171 if (text_input_client_ != client) 172 return; 173 SetFocusedTextInputClient(NULL); 174 } 175 176 virtual TextInputClient* GetTextInputClient() const OVERRIDE { 177 return text_input_client_; 178 } 179 180 virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE { 181 if (event.HasNativeEvent()) { 182 const base::NativeEvent& native_key_event = event.native_event(); 183 if (native_key_event.message != WM_CHAR) 184 return false; 185 if (!text_input_client_) 186 return false; 187 text_input_client_->InsertChar( 188 static_cast<char16>(native_key_event.wParam), 189 ui::GetModifiersFromKeyState()); 190 return true; 191 } 192 193 if (event.is_char()) { 194 if (text_input_client_) { 195 text_input_client_->InsertChar(event.key_code(), 196 ui::GetModifiersFromKeyState()); 197 } 198 return true; 199 } 200 if (!delegate_) 201 return false; 202 return delegate_->DispatchFabricatedKeyEventPostIME(event.type(), 203 event.key_code(), 204 event.flags()); 205 } 206 207 virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE { 208 if (!text_input_client_ || text_input_client_ != client) 209 return; 210 std::vector<int32> prev_input_scopes; 211 std::swap(input_scopes_, prev_input_scopes); 212 input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(), 213 client->GetTextInputMode()); 214 if (input_scopes_ != prev_input_scopes && remote_delegate_) { 215 remote_delegate_->OnTextInputClientUpdated( 216 input_scopes_, composition_character_bounds_); 217 } 218 } 219 220 virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE { 221 if (!text_input_client_ || text_input_client_ != client) 222 return; 223 std::vector<gfx::Rect> prev_rects; 224 std::swap(composition_character_bounds_, prev_rects); 225 composition_character_bounds_ = GetCompositionCharacterBounds(client); 226 if (composition_character_bounds_ != prev_rects && remote_delegate_) { 227 remote_delegate_->OnTextInputClientUpdated( 228 input_scopes_, composition_character_bounds_); 229 } 230 } 231 232 virtual void CancelComposition(const TextInputClient* client) OVERRIDE { 233 if (CanSendRemoteNotification(client)) 234 remote_delegate_->CancelComposition(); 235 } 236 237 virtual void OnInputLocaleChanged() OVERRIDE { 238 } 239 240 virtual std::string GetInputLocale() OVERRIDE { 241 const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT); 242 std::string language = 243 GetLocaleString(locale_id, LOCALE_SISO639LANGNAME); 244 if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty()) 245 return language; 246 const std::string& region = 247 GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME); 248 if (region.empty()) 249 return language; 250 return language.append(1, '-').append(region); 251 } 252 253 virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE { 254 switch (PRIMARYLANGID(langid_)) { 255 case LANG_ARABIC: 256 case LANG_HEBREW: 257 case LANG_PERSIAN: 258 case LANG_SYRIAC: 259 case LANG_UIGHUR: 260 case LANG_URDU: 261 return base::i18n::RIGHT_TO_LEFT; 262 default: 263 return base::i18n::LEFT_TO_RIGHT; 264 } 265 } 266 267 virtual bool IsActive() OVERRIDE { 268 return true; // always turned on 269 } 270 271 virtual TextInputType GetTextInputType() const OVERRIDE { 272 return text_input_client_ ? text_input_client_->GetTextInputType() 273 : TEXT_INPUT_TYPE_NONE; 274 } 275 276 virtual TextInputMode GetTextInputMode() const OVERRIDE { 277 return text_input_client_ ? text_input_client_->GetTextInputMode() 278 : TEXT_INPUT_MODE_DEFAULT; 279 } 280 281 virtual bool CanComposeInline() const OVERRIDE { 282 return text_input_client_ ? text_input_client_->CanComposeInline() : true; 283 } 284 285 virtual bool IsCandidatePopupOpen() const OVERRIDE { 286 return is_candidate_popup_open_; 287 } 288 289 virtual void AddObserver(InputMethodObserver* observer) OVERRIDE { 290 observer_list_.AddObserver(observer); 291 } 292 293 virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE { 294 observer_list_.RemoveObserver(observer); 295 } 296 297 // Overridden from RemoteInputMethodPrivateWin: 298 virtual void SetRemoteDelegate( 299 internal::RemoteInputMethodDelegateWin* delegate) OVERRIDE{ 300 remote_delegate_ = delegate; 301 302 // Sync initial state. 303 if (remote_delegate_) { 304 remote_delegate_->OnTextInputClientUpdated( 305 input_scopes_, composition_character_bounds_); 306 } 307 } 308 309 virtual void OnCandidatePopupChanged(bool visible) OVERRIDE { 310 is_candidate_popup_open_ = visible; 311 } 312 313 virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) OVERRIDE { 314 // Note: Currently |is_ime| is not utilized yet. 315 const bool changed = (langid_ != langid); 316 langid_ = langid; 317 if (changed && GetTextInputClient()) 318 GetTextInputClient()->OnInputMethodChanged(); 319 } 320 321 virtual void OnCompositionChanged( 322 const CompositionText& composition_text) OVERRIDE { 323 if (!text_input_client_) 324 return; 325 text_input_client_->SetCompositionText(composition_text); 326 } 327 328 virtual void OnTextCommitted(const base::string16& text) OVERRIDE { 329 if (!text_input_client_) 330 return; 331 if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) { 332 // According to the comment in text_input_client.h, 333 // TextInputClient::InsertText should never be called when the 334 // text input type is TEXT_INPUT_TYPE_NONE. 335 for (size_t i = 0; i < text.size(); ++i) 336 text_input_client_->InsertChar(text[i], 0); 337 return; 338 } 339 text_input_client_->InsertText(text); 340 } 341 342 bool CanSendRemoteNotification( 343 const TextInputClient* text_input_client) const { 344 return text_input_client_ && 345 text_input_client_ == text_input_client && 346 remote_delegate_; 347 } 348 349 ObserverList<InputMethodObserver> observer_list_; 350 351 internal::InputMethodDelegate* delegate_; 352 internal::RemoteInputMethodDelegateWin* remote_delegate_; 353 354 TextInputClient* text_input_client_; 355 std::vector<int32> input_scopes_; 356 std::vector<gfx::Rect> composition_character_bounds_; 357 bool is_candidate_popup_open_; 358 bool is_ime_; 359 LANGID langid_; 360 361 DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin); 362 }; 363 364 } // namespace 365 366 bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) { 367 DWORD process_id = 0; 368 if (GetWindowThreadProcessId(widget, &process_id) == 0) 369 return false; 370 base::win::ScopedHandle process_handle(::OpenProcess( 371 PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id)); 372 if (!process_handle.IsValid()) 373 return false; 374 return base::win::IsProcessImmersive(process_handle.Get()); 375 } 376 377 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {} 378 379 scoped_ptr<InputMethod> CreateRemoteInputMethodWin( 380 internal::InputMethodDelegate* delegate) { 381 return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate)); 382 } 383 384 // static 385 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get( 386 InputMethod* input_method) { 387 return GetPrivate(input_method); 388 } 389 390 } // namespace ui 391