Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(220)

Side by Side Diff: ui/base/ime/remote_input_method_win.cc

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/base/ime/remote_input_method_win.h ('k') | ui/base/ime/remote_input_method_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 bool CanComposeInline() const override {
274 return text_input_client_ ? text_input_client_->CanComposeInline() : true;
275 }
276
277 virtual bool IsCandidatePopupOpen() const override {
278 return is_candidate_popup_open_;
279 }
280
281 virtual void ShowImeIfNeeded() override {
282 }
283
284 virtual void AddObserver(InputMethodObserver* observer) override {
285 observer_list_.AddObserver(observer);
286 }
287
288 virtual void RemoveObserver(InputMethodObserver* observer) override {
289 observer_list_.RemoveObserver(observer);
290 }
291
292 // Overridden from RemoteInputMethodPrivateWin:
293 virtual void SetRemoteDelegate(
294 internal::RemoteInputMethodDelegateWin* delegate) override{
295 remote_delegate_ = delegate;
296
297 // Sync initial state.
298 if (remote_delegate_) {
299 remote_delegate_->OnTextInputClientUpdated(
300 input_scopes_, composition_character_bounds_);
301 }
302 }
303
304 virtual void OnCandidatePopupChanged(bool visible) override {
305 is_candidate_popup_open_ = visible;
306 if (!text_input_client_)
307 return;
308 // TODO(kochi): Support 'update' case, in addition to show/hide.
309 // http://crbug.com/238585
310 if (visible)
311 text_input_client_->OnCandidateWindowShown();
312 else
313 text_input_client_->OnCandidateWindowHidden();
314 }
315
316 virtual void OnInputSourceChanged(LANGID langid, bool /*is_ime*/) override {
317 // Note: Currently |is_ime| is not utilized yet.
318 const bool changed = (langid_ != langid);
319 langid_ = langid;
320 if (changed && GetTextInputClient())
321 GetTextInputClient()->OnInputMethodChanged();
322 }
323
324 virtual void OnCompositionChanged(
325 const CompositionText& composition_text) override {
326 if (!text_input_client_)
327 return;
328 text_input_client_->SetCompositionText(composition_text);
329 }
330
331 virtual void OnTextCommitted(const base::string16& text) override {
332 if (!text_input_client_)
333 return;
334 if (text_input_client_->GetTextInputType() == TEXT_INPUT_TYPE_NONE) {
335 // According to the comment in text_input_client.h,
336 // TextInputClient::InsertText should never be called when the
337 // text input type is TEXT_INPUT_TYPE_NONE.
338 for (size_t i = 0; i < text.size(); ++i)
339 text_input_client_->InsertChar(text[i], 0);
340 return;
341 }
342 text_input_client_->InsertText(text);
343 }
344
345 bool CanSendRemoteNotification(
346 const TextInputClient* text_input_client) const {
347 return text_input_client_ &&
348 text_input_client_ == text_input_client &&
349 remote_delegate_;
350 }
351
352 ObserverList<InputMethodObserver> observer_list_;
353
354 internal::InputMethodDelegate* delegate_;
355 internal::RemoteInputMethodDelegateWin* remote_delegate_;
356
357 TextInputClient* text_input_client_;
358 std::vector<int32> input_scopes_;
359 std::vector<gfx::Rect> composition_character_bounds_;
360 bool is_candidate_popup_open_;
361 bool is_ime_;
362 LANGID langid_;
363
364 DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
365 };
366
367 } // namespace
368
369 bool IsRemoteInputMethodWinRequired(gfx::AcceleratedWidget widget) {
370 // If the remote input method is already registered then don't do it again.
371 if (ui::g_public_interface_ && ui::g_private_interface_)
372 return false;
373
374 DWORD process_id = 0;
375 if (GetWindowThreadProcessId(widget, &process_id) == 0)
376 return false;
377 base::win::ScopedHandle process_handle(::OpenProcess(
378 PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id));
379 if (!process_handle.IsValid())
380 return false;
381 return base::win::IsProcessImmersive(process_handle.Get()) ||
382 CommandLine::ForCurrentProcess()->HasSwitch(
383 switches::kViewerConnect);
384 }
385
386 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
387
388 scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
389 internal::InputMethodDelegate* delegate) {
390 return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate));
391 }
392
393 // static
394 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
395 InputMethod* input_method) {
396 return GetPrivate(input_method);
397 }
398
399 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/ime/remote_input_method_win.h ('k') | ui/base/ime/remote_input_method_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698