Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / base / ime / remote_input_method_win.cc
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/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/rect.h"
22
23 namespace ui {
24 namespace {
25
26 const LANGID kFallbackLangID =
27     MAKELANGID(LANG_NEUTRAL, SUBLANG_UI_CUSTOM_DEFAULT);
28
29 InputMethod* g_public_interface_ = NULL;
30 RemoteInputMethodPrivateWin* g_private_interface_ = NULL;
31
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;
40 }
41
42 RemoteInputMethodPrivateWin* GetPrivate(InputMethod* public_interface) {
43   if (g_public_interface_ != public_interface)
44     return NULL;
45   return g_private_interface_;
46 }
47
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;
54   }
55 }
56
57 std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
58   wchar_t buffer[16] = {};
59
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;
68 }
69
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;
76
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;
83 }
84
85 std::vector<gfx::Rect> GetCompositionCharacterBounds(
86     const TextInputClient* client) {
87   if (!client)
88     return std::vector<gfx::Rect>();
89
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);
99       }
100     }
101   }
102
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;
109 }
110
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);
122   }
123
124   virtual ~RemoteInputMethodWin() {
125     FOR_EACH_OBSERVER(InputMethodObserver,
126                       observer_list_,
127                       OnInputMethodDestroyed(this));
128     UnregisterInstance(this);
129   }
130
131  private:
132   // Overridden from InputMethod:
133   virtual void SetDelegate(internal::InputMethodDelegate* delegate) override {
134     delegate_ = delegate;
135   }
136
137   virtual void Init(bool focused) override {
138   }
139
140   virtual void OnFocus() override {
141   }
142
143   virtual void OnBlur() override {
144   }
145
146   virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
147                                         NativeEventResult* result) override {
148     return false;
149   }
150
151   virtual void SetFocusedTextInputClient(TextInputClient* client) override {
152     std::vector<int32> prev_input_scopes;
153     std::swap(input_scopes_, prev_input_scopes);
154     std::vector<gfx::Rect> prev_bounds;
155     std::swap(composition_character_bounds_, prev_bounds);
156     if (client) {
157       input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
158                                           client->GetTextInputMode());
159       composition_character_bounds_ = GetCompositionCharacterBounds(client);
160     }
161
162     const bool text_input_client_changed = text_input_client_ != client;
163     text_input_client_ = client;
164     if (text_input_client_changed) {
165       FOR_EACH_OBSERVER(InputMethodObserver,
166                         observer_list_,
167                         OnTextInputStateChanged(client));
168     }
169
170     if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
171                               prev_bounds == composition_character_bounds_))
172       return;
173     remote_delegate_->OnTextInputClientUpdated(input_scopes_,
174                                                composition_character_bounds_);
175   }
176
177   virtual void DetachTextInputClient(TextInputClient* client) override {
178     if (text_input_client_ != client)
179       return;
180     SetFocusedTextInputClient(NULL);
181   }
182
183   virtual TextInputClient* GetTextInputClient() const override {
184     return text_input_client_;
185   }
186
187   virtual bool DispatchKeyEvent(const ui::KeyEvent& event) override {
188     if (event.HasNativeEvent()) {
189       const base::NativeEvent& native_key_event = event.native_event();
190       if (native_key_event.message != WM_CHAR)
191         return false;
192       if (!text_input_client_)
193         return false;
194       text_input_client_->InsertChar(
195           static_cast<base::char16>(native_key_event.wParam),
196           ui::GetModifiersFromKeyState());
197       return true;
198     }
199
200     if (event.is_char()) {
201       if (text_input_client_) {
202         text_input_client_->InsertChar(
203             static_cast<base::char16>(event.key_code()),
204             ui::GetModifiersFromKeyState());
205       }
206       return true;
207     }
208     if (!delegate_)
209       return false;
210     return delegate_->DispatchKeyEventPostIME(event);
211   }
212
213   virtual void OnTextInputTypeChanged(const TextInputClient* client) override {
214     if (!text_input_client_ || text_input_client_ != client)
215       return;
216     std::vector<int32> prev_input_scopes;
217     std::swap(input_scopes_, prev_input_scopes);
218     input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
219                                         client->GetTextInputMode());
220     if (input_scopes_ != prev_input_scopes && remote_delegate_) {
221       remote_delegate_->OnTextInputClientUpdated(
222           input_scopes_, composition_character_bounds_);
223     }
224   }
225
226   virtual void OnCaretBoundsChanged(const TextInputClient* client) override {
227     if (!text_input_client_ || text_input_client_ != client)
228       return;
229     std::vector<gfx::Rect> prev_rects;
230     std::swap(composition_character_bounds_, prev_rects);
231     composition_character_bounds_ = GetCompositionCharacterBounds(client);
232     if (composition_character_bounds_ != prev_rects && remote_delegate_) {
233       remote_delegate_->OnTextInputClientUpdated(
234           input_scopes_, composition_character_bounds_);
235     }
236   }
237
238   virtual void CancelComposition(const TextInputClient* client) override {
239     if (CanSendRemoteNotification(client))
240       remote_delegate_->CancelComposition();
241   }
242
243   virtual void OnInputLocaleChanged() override {
244   }
245
246   virtual std::string GetInputLocale() override {
247     const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
248     std::string language =
249         GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
250     if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
251       return language;
252     const std::string& region =
253         GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
254     if (region.empty())
255       return language;
256     return language.append(1, '-').append(region);
257   }
258
259   virtual bool IsActive() override {
260     return true;  // always turned on
261   }
262
263   virtual TextInputType GetTextInputType() const override {
264     return text_input_client_ ? text_input_client_->GetTextInputType()
265                               : TEXT_INPUT_TYPE_NONE;
266   }
267
268   virtual TextInputMode GetTextInputMode() const override {
269     return text_input_client_ ? text_input_client_->GetTextInputMode()
270                               : TEXT_INPUT_MODE_DEFAULT;
271   }
272
273   virtual int GetTextInputFlags() const override {
274     return text_input_client_ ? text_input_client_->GetTextInputFlags()
275                               : 0;
276   }
277
278   virtual bool CanComposeInline() const override {
279     return text_input_client_ ? text_input_client_->CanComposeInline() : true;
280   }
281
282   virtual bool IsCandidatePopupOpen() const override {
283     return is_candidate_popup_open_;
284   }
285
286   virtual void ShowImeIfNeeded() override {
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     if (!text_input_client_)
312       return;
313     // TODO(kochi): Support 'update' case, in addition to show/hide.
314     // http://crbug.com/238585
315     if (visible)
316       text_input_client_->OnCandidateWindowShown();
317     else
318       text_input_client_->OnCandidateWindowHidden();
319   }
320
321   virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) override {
322     // Note: Currently |is_ime| is not utilized yet.
323     const bool changed = (langid_ != langid);
324     langid_ = langid;
325     if (changed && GetTextInputClient())
326       GetTextInputClient()->OnInputMethodChanged();
327   }
328
329   virtual void OnCompositionChanged(
330       const CompositionText& composition_text) override {
331     if (!text_input_client_)
332       return;
333     text_input_client_->SetCompositionText(composition_text);
334   }
335
336   virtual void OnTextCommitted(const base::string16& text) override {
337     if (!text_input_client_)
338       return;
339     if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) {
340       // According to the comment in text_input_client.h,
341       // TextInputClient::InsertText should never be called when the
342       // text input type is TEXT_INPUT_TYPE_NONE.
343       for (size_t i = 0; i < text.size(); ++i)
344         text_input_client_->InsertChar(text[i], 0);
345       return;
346     }
347     text_input_client_->InsertText(text);
348   }
349
350   bool CanSendRemoteNotification(
351       const TextInputClient* text_input_client) const {
352     return text_input_client_ &&
353            text_input_client_ == text_input_client &&
354            remote_delegate_;
355   }
356
357   ObserverList<InputMethodObserver> observer_list_;
358
359   internal::InputMethodDelegate* delegate_;
360   internal::RemoteInputMethodDelegateWin* remote_delegate_;
361
362   TextInputClient* text_input_client_;
363   std::vector<int32> input_scopes_;
364   std::vector<gfx::Rect> composition_character_bounds_;
365   bool is_candidate_popup_open_;
366   bool is_ime_;
367   LANGID langid_;
368
369   DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
370 };
371
372 }  // namespace
373
374 bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) {
375   // If the remote input method is already registered then don't do it again.
376   if (ui::g_public_interface_ && ui::g_private_interface_)
377     return false;
378
379   DWORD process_id = 0;
380   if (GetWindowThreadProcessId(widget, &process_id) == 0)
381     return false;
382   base::win::ScopedHandle process_handle(::OpenProcess(
383       PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
384   if (!process_handle.IsValid())
385     return false;
386   return base::win::IsProcessImmersive(process_handle.Get()) ||
387          CommandLine::ForCurrentProcess()->HasSwitch(
388             switches::kViewerConnect);
389 }
390
391 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
392
393 scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
394     internal::InputMethodDelegate* delegate) {
395   return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate));
396 }
397
398 // static
399 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
400     InputMethod* input_method) {
401   return GetPrivate(input_method);
402 }
403
404 }  // namespace ui