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