Update V8 to version 4.7.45.
[chromium-blink-merge.git] / ui / base / ime / remote_input_method_win.cc
blob1a589bb0668f6b235b24f755093c2812abd512fb
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.
5 #include "ui/base/ime/remote_input_method_win.h"
7 #include "base/command_line.h"
8 #include "base/observer_list.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/win/metro.h"
11 #include "base/win/scoped_handle.h"
12 #include "ui/base/ime/input_method.h"
13 #include "ui/base/ime/input_method_delegate.h"
14 #include "ui/base/ime/input_method_observer.h"
15 #include "ui/base/ime/remote_input_method_delegate_win.h"
16 #include "ui/base/ime/text_input_client.h"
17 #include "ui/base/ime/win/tsf_input_scope.h"
18 #include "ui/base/ui_base_switches.h"
19 #include "ui/events/event.h"
20 #include "ui/events/event_utils.h"
21 #include "ui/gfx/geometry/rect.h"
23 namespace ui {
24 namespace {
26 const LANGID kFallbackLangID =
27 MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT);
29 InputMethod* g_public_interface_ = NULL;
30 RemoteInputMethodPrivateWin* g_private_interface_ = NULL;
32 void RegisterInstance(InputMethod* public_interface,
33 RemoteInputMethodPrivateWin* private_interface) {
34 CHECK(g_public_interface_ == NULL)
35 << "Only one instance is supported at the same time";
36 CHECK(g_private_interface_ == NULL)
37 << "Only one instance is supported at the same time";
38 g_public_interface_ = public_interface;
39 g_private_interface_ = private_interface;
42 RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) {
43 if (g_public_interface_ != public_interface)
44 return NULL;
45 return g_private_interface_;
48 void UnregisterInstance(InputMethod* public_interface) {
49 RemoteInputMethodPrivateWin* private_interface = GetPrivate(public_interface);
50 if (g_public_interface_ == public_interface &&
51 g_private_interface_ == private_interface) {
52 g_public_interface_ = NULL;
53 g_private_interface_ = NULL;
57 std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
58 wchar_t buffer[16] = {};
60 //|chars_written| includes NUL terminator.
61 const int chars_written =
62 GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
63 if (chars_written <= 1 || arraysize(buffer) < chars_written)
64 return std::string();
65 std::string result;
66 base::WideToUTF8(buffer, chars_written - 1, &result);
67 return result;
70 std::vector<int32> GetInputScopesAsInt(TextInputType text_input_type,
71 TextInputMode text_input_mode) {
72 std::vector<int32> result;
73 // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE.
74 if (text_input_type == TEXT_INPUT_TYPE_NONE)
75 return result;
77 const std::vector<InputScope>& input_scopes =
78 tsf_inputscope::GetInputScopes(text_input_type, text_input_mode);
79 result.reserve(input_scopes.size());
80 for (size_t i = 0; i < input_scopes.size(); ++i)
81 result.push_back(static_cast<int32>(input_scopes[i]));
82 return result;
85 std::vector<gfx::Rect> GetCompositionCharacterBounds(
86 const TextInputClient* client) {
87 if (!client)
88 return std::vector<gfx::Rect>();
90 std::vector<gfx::Rect> bounds;
91 if (client->HasCompositionText()) {
92 gfx::Range range;
93 if (client->GetCompositionTextRange(&range)) {
94 for (uint32 i = 0; i < range.length(); ++i) {
95 gfx::Rect rect;
96 if (!client->GetCompositionCharacterBounds(i, &rect))
97 break;
98 bounds.push_back(rect);
103 // Use the caret bounds as a fallback if no composition character bounds is
104 // available. One typical use case is PPAPI Flash, which does not support
105 // GetCompositionCharacterBounds at all. crbug.com/133472
106 if (bounds.empty())
107 bounds.push_back(client->GetCaretBounds());
108 return bounds;
111 class RemoteInputMethodWin : public InputMethod,
112 public RemoteInputMethodPrivateWin {
113 public:
114 explicit RemoteInputMethodWin(internal::InputMethodDelegate* delegate)
115 : delegate_(delegate),
116 remote_delegate_(NULL),
117 text_input_client_(NULL),
118 is_candidate_popup_open_(false),
119 is_ime_(false),
120 langid_(kFallbackLangID) {
121 RegisterInstance(this, this);
124 ~RemoteInputMethodWin() override {
125 FOR_EACH_OBSERVER(InputMethodObserver,
126 observer_list_,
127 OnInputMethodDestroyed(this));
128 UnregisterInstance(this);
131 private:
132 // Overridden from InputMethod:
133 void SetDelegate(internal::InputMethodDelegate* delegate) override {
134 delegate_ = delegate;
137 void OnFocus() override {}
139 void OnBlur() override {}
141 bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
142 NativeEventResult* result) override {
143 return false;
146 void SetFocusedTextInputClient(TextInputClient* client) override {
147 std::vector<int32> prev_input_scopes;
148 std::swap(input_scopes_, prev_input_scopes);
149 std::vector<gfx::Rect> prev_bounds;
150 std::swap(composition_character_bounds_, prev_bounds);
151 if (client) {
152 input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
153 client->GetTextInputMode());
154 composition_character_bounds_ = GetCompositionCharacterBounds(client);
157 const bool text_input_client_changed = text_input_client_ != client;
158 text_input_client_ = client;
159 if (text_input_client_changed) {
160 FOR_EACH_OBSERVER(InputMethodObserver,
161 observer_list_,
162 OnTextInputStateChanged(client));
165 if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
166 prev_bounds == composition_character_bounds_))
167 return;
168 remote_delegate_->OnTextInputClientUpdated(input_scopes_,
169 composition_character_bounds_);
172 void DetachTextInputClient(TextInputClient* client) override {
173 if (text_input_client_ != client)
174 return;
175 SetFocusedTextInputClient(NULL);
178 TextInputClient* GetTextInputClient() const override {
179 return text_input_client_;
182 void DispatchKeyEvent(ui::KeyEvent* event) override {
183 if (event->HasNativeEvent()) {
184 const base::NativeEvent& native_key_event = event->native_event();
185 if (native_key_event.message == WM_CHAR && text_input_client_) {
186 text_input_client_->InsertChar(
187 static_cast<base::char16>(native_key_event.wParam),
188 ui::GetModifiersFromKeyState());
189 event->StopPropagation();
191 return;
194 if (event->is_char()) {
195 if (text_input_client_) {
196 text_input_client_->InsertChar(
197 event->GetCharacter(),
198 ui::GetModifiersFromKeyState());
200 event->StopPropagation();
201 return;
203 if (delegate_)
204 ignore_result(delegate_->DispatchKeyEventPostIME(event));
207 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_);
220 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_);
232 void CancelComposition(const TextInputClient* client) override {
233 if (CanSendRemoteNotification(client))
234 remote_delegate_->CancelComposition();
237 void OnInputLocaleChanged() override {}
239 std::string GetInputLocale() override {
240 const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
241 std::string language =
242 GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
243 if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
244 return language;
245 const std::string& region =
246 GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
247 if (region.empty())
248 return language;
249 return language.append(1, '-').append(region);
252 TextInputType GetTextInputType() const override {
253 return text_input_client_ ? text_input_client_->GetTextInputType()
254 : TEXT_INPUT_TYPE_NONE;
257 TextInputMode GetTextInputMode() const override {
258 return text_input_client_ ? text_input_client_->GetTextInputMode()
259 : TEXT_INPUT_MODE_DEFAULT;
262 int GetTextInputFlags() const override {
263 return text_input_client_ ? text_input_client_->GetTextInputFlags()
264 : 0;
267 bool CanComposeInline() const override {
268 return text_input_client_ ? text_input_client_->CanComposeInline() : true;
271 bool IsCandidatePopupOpen() const override {
272 return is_candidate_popup_open_;
275 void ShowImeIfNeeded() override {}
277 void AddObserver(InputMethodObserver* observer) override {
278 observer_list_.AddObserver(observer);
281 void RemoveObserver(InputMethodObserver* observer) override {
282 observer_list_.RemoveObserver(observer);
285 // Overridden from RemoteInputMethodPrivateWin:
286 void SetRemoteDelegate(
287 internal::RemoteInputMethodDelegateWin* delegate) override {
288 remote_delegate_ = delegate;
290 // Sync initial state.
291 if (remote_delegate_) {
292 remote_delegate_->OnTextInputClientUpdated(
293 input_scopes_, composition_character_bounds_);
297 void OnCandidatePopupChanged(bool visible) override {
298 is_candidate_popup_open_ = visible;
301 void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) override {
302 // Note: Currently |is_ime| is not utilized yet.
303 const bool changed = (langid_ != langid);
304 langid_ = langid;
305 if (changed && GetTextInputClient())
306 GetTextInputClient()->OnInputMethodChanged();
309 void OnCompositionChanged(const CompositionText& composition_text) override {
310 if (!text_input_client_)
311 return;
312 text_input_client_->SetCompositionText(composition_text);
315 void OnTextCommitted(const base::string16& text) override {
316 if (!text_input_client_)
317 return;
318 if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) {
319 // According to the comment in text_input_client.h,
320 // TextInputClient::InsertText should never be called when the
321 // text input type is TEXT_INPUT_TYPE_NONE.
322 for (size_t i = 0; i < text.size(); ++i)
323 text_input_client_->InsertChar(text[i], 0);
324 return;
326 text_input_client_->InsertText(text);
329 bool CanSendRemoteNotification(
330 const TextInputClient* text_input_client) const {
331 return text_input_client_ &&
332 text_input_client_ == text_input_client &&
333 remote_delegate_;
336 base::ObserverList<InputMethodObserver> observer_list_;
338 internal::InputMethodDelegate* delegate_;
339 internal::RemoteInputMethodDelegateWin* remote_delegate_;
341 TextInputClient* text_input_client_;
342 std::vector<int32> input_scopes_;
343 std::vector<gfx::Rect> composition_character_bounds_;
344 bool is_candidate_popup_open_;
345 bool is_ime_;
346 LANGID langid_;
348 DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
351 } // namespace
353 bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) {
354 // If the remote input method is already registered then don't do it again.
355 if (ui::g_public_interface_ && ui::g_private_interface_)
356 return false;
358 DWORD process_id = 0;
359 if (GetWindowThreadProcessId(widget, &process_id) == 0)
360 return false;
361 base::win::ScopedHandle process_handle(::OpenProcess(
362 PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
363 if (!process_handle.IsValid())
364 return false;
365 return base::win::IsProcessImmersive(process_handle.Get()) ||
366 base::CommandLine::ForCurrentProcess()->HasSwitch(
367 switches::kViewerConnect);
370 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
372 scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
373 internal::InputMethodDelegate* delegate) {
374 return make_scoped_ptr(new RemoteInputMethodWin(delegate));
377 // static
378 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
379 InputMethod* input_method) {
380 return GetPrivate(input_method);
383 } // namespace ui