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

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

Issue 67503004: Introduce RemoteInputMethodWin (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 1 month 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
OLDNEW
(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 // Caveats: Currently we support only one instance at the same time.
Seigo Nonaka 2013/11/18 20:00:27 Could you describe why should we support multiple
yukawa 2013/11/19 07:17:51 I don't think we need to support multiple instance
24 class InstanceMapper {
Seigo Nonaka 2013/11/18 20:00:27 Does this class is necessary? Seems there is only
yukawa 2013/11/19 07:17:51 Done.
25 public:
26 static void RegisterInstance(InputMethod* public_interface,
27 RemoteInputMethodPrivateWin* private_interface) {
28 CHECK(public_interface_ == NULL)
29 << "Currently only one instance is supported at the same time";
30 CHECK(private_interface_ == NULL)
31 << "Currently only one instance is supported at the same time";
32 public_interface_ = public_interface;
33 private_interface_ = private_interface;
34 }
35
36 static void UnregisterInstance(InputMethod* public_interface) {
37 RemoteInputMethodPrivateWin* private_interface =
38 GetPrivate(public_interface);
39 if (public_interface_ == public_interface &&
40 private_interface_ == private_interface) {
41 public_interface_ = NULL;
42 private_interface_ = NULL;
43 }
44 }
45
46 static RemoteInputMethodPrivateWin* GetPrivate(
47 InputMethod* public_interface) {
48 if (public_interface_ != public_interface)
49 return NULL;
50 return private_interface_;
51 }
52
53 private:
54 static InputMethod* public_interface_;
55 static RemoteInputMethodPrivateWin* private_interface_;
56
57 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceMapper);
58 };
59 InputMethod* InstanceMapper::public_interface_ = NULL;
60 RemoteInputMethodPrivateWin* InstanceMapper::private_interface_ = NULL;
61
62 std::string GetLocaleString(LCID Locale_id, LCTYPE locale_type) {
63 wchar_t buffer[16] = {};
64
65 //|chars_written| includes NUL terminator.
66 int chars_written =
67 GetLocaleInfo(Locale_id, locale_type, buffer, arraysize(buffer));
68 if (chars_written <= 1 || arraysize(buffer) < chars_written)
69 return std::string();
70 std::string result;
71 WideToUTF8(buffer, chars_written - 1, &result);
72 return result;
73 }
74
75 std::vector<int32> GetInputScopesAsInt(TextInputType text_input_type,
76 TextInputMode text_input_mode) {
77 std::vector<int32> result;
78 // An empty vector represents |text_input_type| is TEXT_INPUT_TYPE_NONE.
79 if (text_input_type == TEXT_INPUT_TYPE_NONE)
80 return result;
81
82 const std::vector<InputScope>& input_scopes =
83 tsf_inputscope::GetInputScopes(text_input_type, text_input_mode);
84 result.reserve(input_scopes.size());
85 for (size_t i = 0; i < input_scopes.size(); ++i)
86 result.push_back(static_cast<int32>(input_scopes[i]));
87 return result;
88 }
89
90 std::vector<gfx::Rect> GetCompositionCharacterBounds(
91 const TextInputClient* client) {
92 if (!client)
93 return std::vector<gfx::Rect>();
94
95 if (!client->HasCompositionText()) {
96 std::vector<gfx::Rect> caret;
97 caret.push_back(client->GetCaretBounds());
98 return caret;
99 }
100
101 std::vector<gfx::Rect> bounds;
102 for (uint32 i = 0;; ++i) {
103 gfx::Rect rect;
104 if (!client->GetCompositionCharacterBounds(i, &rect))
105 break;
106 bounds.push_back(rect);
107 }
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 InstanceMapper::RegisterInstance(this, this);
122 }
Seigo Nonaka 2013/11/18 20:00:27 plz add one line break between functions.
yukawa 2013/11/19 07:17:51 Done.
123 virtual ~RemoteInputMethodWin() {
124 InstanceMapper::UnregisterInstance(this);
125 }
126
127 private:
128 // Overridden from InputMethod:
129 virtual void SetDelegate(internal::InputMethodDelegate* delegate) OVERRIDE {
130 delegate_ = delegate;
131 }
132 virtual void Init(bool focused) OVERRIDE {}
133 virtual void OnFocus() OVERRIDE {}
134 virtual void OnBlur() OVERRIDE {}
135 virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
136 NativeEventResult* result) OVERRIDE {
137 return false;
138 }
139 virtual void SetFocusedTextInputClient(TextInputClient* client) OVERRIDE {
140
141 std::vector<int32> prev_input_scopes;
142 std::swap(input_scopes_, prev_input_scopes);
143 std::vector<gfx::Rect> prev_bounds;
144 std::swap(composition_character_bounds_, prev_bounds);
145 if (client) {
146 input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
147 client->GetTextInputMode());
148 composition_character_bounds_ = GetCompositionCharacterBounds(client);
149 }
150
151 text_input_client_ = client;
152
153 if (!remote_delegate_ || (prev_input_scopes == input_scopes_ &&
154 prev_bounds == composition_character_bounds_))
155 return;
156 remote_delegate_->OnTextInputClientUpdated(
157 input_scopes_, composition_character_bounds_);
158 }
159 virtual void DetachTextInputClient(TextInputClient* client) OVERRIDE {
160 if (text_input_client_ == client) {
Seigo Nonaka 2013/11/18 20:00:27 nit: I prefer early exit style but up to you.
yukawa 2013/11/19 07:17:51 Done. And simplified.
161 if (!input_scopes_.empty() || !composition_character_bounds_.empty()) {
162 input_scopes_.empty();
163 composition_character_bounds_.empty();
164 if (remote_delegate_) {
165 remote_delegate_->OnTextInputClientUpdated(
166 input_scopes_, composition_character_bounds_);
167 }
168 }
169 text_input_client_ = NULL;
170 }
171 }
172 virtual TextInputClient* GetTextInputClient() const OVERRIDE {
173 return text_input_client_;
174 }
175 virtual bool DispatchKeyEvent(const ui::KeyEvent& event) OVERRIDE {
176 if (event.HasNativeEvent())
Seigo Nonaka 2013/11/18 20:00:27 DCHECK?
yukawa 2013/11/19 07:17:51 Um, I changed my mind and added WM_CHAR handler be
Seigo Nonaka 2013/11/20 04:14:29 Let me confirm again, will RemoteInputMethodWin di
yukawa 2013/11/20 05:06:07 Do you mean we should do as follows? if (event.Ha
Seigo Nonaka 2013/11/20 05:40:41 Okay, as we talked offline, it seems good to imple
177 return false;
178
179 if (event.is_char() && text_input_client_) {
180 GetTextInputClient()->InsertChar(event.key_code(),
181 ui::GetModifiersFromKeyState());
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 virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE {
191 if (!text_input_client_ || text_input_client_ != client)
192 return;
193 std::vector<int32> prev_input_scopes;
194 std::swap(input_scopes_, prev_input_scopes);
195 input_scopes_ = GetInputScopesAsInt(client->GetTextInputType(),
196 client->GetTextInputMode());
197 if (input_scopes_ != prev_input_scopes && remote_delegate_) {
198 remote_delegate_->OnTextInputClientUpdated(
199 input_scopes_, composition_character_bounds_);
200 }
201 }
202 virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE {
203 if (!text_input_client_ || text_input_client_ != client)
204 return;
205 std::vector<gfx::Rect> prev_rects;
206 std::swap(composition_character_bounds_, prev_rects);
207 composition_character_bounds_ = GetCompositionCharacterBounds(client);
208 if (composition_character_bounds_ != prev_rects && remote_delegate_) {
209 remote_delegate_->OnTextInputClientUpdated(
210 input_scopes_, composition_character_bounds_);
211 }
212 }
213 virtual void CancelComposition(const TextInputClient* client) OVERRIDE {
214 if (CanSendRemoteNotification(client))
215 remote_delegate_->CancelComposition();
216 }
217 virtual void OnInputLocaleChanged() OVERRIDE {
218 // not supported.
219 }
220 virtual std::string GetInputLocale() OVERRIDE {
221 const LCID locale_id = MAKELCID(langid_, SORT_DEFAULT);
222 std::string language =
223 GetLocaleString(locale_id, LOCALE_SISO639LANGNAME);
224 if (SUBLANGID(langid_) == SUBLANG_NEUTRAL || language.empty())
225 return language;
226 const std::string& region =
227 GetLocaleString(locale_id, LOCALE_SISO3166CTRYNAME);
228 if (region.empty())
229 return language;
230 return language.append(1, '-').append(region);
231 }
232 virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE {
233 switch (PRIMARYLANGID(langid_)) {
234 case LANG_ARABIC:
235 case LANG_HEBREW:
236 case LANG_PERSIAN:
237 case LANG_SYRIAC:
238 case LANG_UIGHUR:
239 case LANG_URDU:
240 return base::i18n::RIGHT_TO_LEFT;
241 default:
242 return base::i18n::LEFT_TO_RIGHT;
243 }
244 }
245 virtual bool IsActive() OVERRIDE {
246 return true; // always turned on
247 }
248 virtual TextInputType GetTextInputType() const OVERRIDE {
249 return text_input_client_ ? text_input_client_->GetTextInputType()
250 : TEXT_INPUT_TYPE_NONE;
251 }
252 virtual TextInputMode GetTextInputMode() const OVERRIDE {
253 return text_input_client_ ? text_input_client_->GetTextInputMode()
254 : TEXT_INPUT_MODE_DEFAULT;
255 }
256 virtual bool CanComposeInline() const OVERRIDE {
257 return text_input_client_ ? text_input_client_->CanComposeInline() : true;
258 }
259 virtual bool IsCandidatePopupOpen() const OVERRIDE {
260 return is_candidate_popup_open_;
261 }
262 virtual void AddObserver(InputMethodObserver* observer) OVERRIDE {
263 // not supported.
Seigo Nonaka 2013/11/18 20:00:27 If you will support this, please file a bug and le
yukawa 2013/11/19 07:17:51 I don't want to support this. IMHO, I'd like to d
264 }
265 virtual void RemoveObserver(InputMethodObserver* observer) OVERRIDE {
266 // not supported.
267 }
268
269 // Overridden from RemoteInputMethodPrivateWin:
270 virtual void SetRemoteDelegate(
271 internal::RemoteInputMethodDelegateWin* delegate) OVERRIDE{
272 remote_delegate_ = delegate;
273
274 // Sync initial state.
275 if (remote_delegate_) {
276 remote_delegate_->OnTextInputClientUpdated(
277 input_scopes_, composition_character_bounds_);
278 }
279 }
280 virtual void OnCandidatePopupChanged(bool visible) OVERRIDE {
281 is_candidate_popup_open_ = visible;
282 }
283 virtual void OnLanguageChanged(LANGID langid, bool /*is_ime*/) OVERRIDE {
284 // Note: Currently |is_ime| is not utilized yet.
285 const bool changed = (langid_ != langid);
286 langid_ = langid;
287 if (changed && GetTextInputClient())
288 GetTextInputClient()->OnInputMethodChanged();
289 }
290
291 bool CanSendRemoteNotification(
292 const TextInputClient* text_input_client) const {
293 return text_input_client_ &&
294 text_input_client_ == text_input_client &&
295 remote_delegate_;
296 }
297
298 internal::InputMethodDelegate* delegate_;
299 internal::RemoteInputMethodDelegateWin* remote_delegate_;
300
301 TextInputClient* text_input_client_;
302 std::vector<int32> input_scopes_;
303 std::vector<gfx::Rect> composition_character_bounds_;
304 bool is_candidate_popup_open_;
305 bool is_ime_;
306 LANGID langid_;
307
308 DISALLOW_COPY_AND_ASSIGN(RemoteInputMethodWin);
309 };
310
311 } // namespace
312
313 RemoteInputMethodPrivateWin::RemoteInputMethodPrivateWin() {}
314
315 // static
316 scoped_ptr<InputMethod> CreateRemoteInputMethodWin(
317 internal::InputMethodDelegate* delegate) {
318 return scoped_ptr<InputMethod>(new RemoteInputMethodWin(delegate));
319 }
320
321 // static
322 RemoteInputMethodPrivateWin* RemoteInputMethodPrivateWin::Get(
323 InputMethod* input_method) {
324 return InstanceMapper::GetPrivate(input_method);
325 }
326
327 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698