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

Side by Side Diff: ui/base/win/ime_input.cc

Issue 6709023: Move some common ime code to ui/base/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Always put the composition cursor to the selection end. Created 9 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « ui/base/win/ime_input.h ('k') | ui/ui_base.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ime_input.h" 5 #include "ui/base/win/ime_input.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/scoped_ptr.h" 8 #include "base/scoped_ptr.h"
9 #include "base/string16.h"
9 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/utf_string_conversions.h"
10 #include "third_party/skia/include/core/SkColor.h" 12 #include "third_party/skia/include/core/SkColor.h"
13 #include "ui/base/ime/composition_text.h"
11 14
12 // "imm32.lib" is required by IMM32 APIs used in this file. 15 // "imm32.lib" is required by IMM32 APIs used in this file.
13 // NOTE(hbono): To comply with a comment from Darin, I have added 16 // NOTE(hbono): To comply with a comment from Darin, I have added
14 // this #pragma directive instead of adding "imm32.lib" to a project file. 17 // this #pragma directive instead of adding "imm32.lib" to a project file.
15 #pragma comment(lib, "imm32.lib") 18 #pragma comment(lib, "imm32.lib")
16 19
20 // Following code requires wchar_t to be same as char16. It should always be
21 // true on Windows.
22 COMPILE_ASSERT(sizeof(wchar_t) == sizeof(char16), wchar_t__char16_diff);
23
17 /////////////////////////////////////////////////////////////////////////////// 24 ///////////////////////////////////////////////////////////////////////////////
18 // ImeInput 25 // ImeInput
19 26
20 namespace { 27 namespace {
21 28
22 // Determines whether or not the given attribute represents a target 29 // Determines whether or not the given attribute represents a target
23 // (a.k.a. a selection). 30 // (a.k.a. a selection).
24 bool IsTargetAttribute(char attribute) { 31 bool IsTargetAttribute(char attribute) {
25 return (attribute == ATTR_TARGET_CONVERTED || 32 return (attribute == ATTR_TARGET_CONVERTED ||
26 attribute == ATTR_TARGET_NOTCONVERTED); 33 attribute == ATTR_TARGET_NOTCONVERTED);
(...skipping 28 matching lines...) Expand all
55 end = attribute_size; 62 end = attribute_size;
56 } 63 }
57 } 64 }
58 *target_start = start; 65 *target_start = start;
59 *target_end = end; 66 *target_end = end;
60 } 67 }
61 } 68 }
62 69
63 // Helper function for ImeInput::GetCompositionInfo() method, to get underlines 70 // Helper function for ImeInput::GetCompositionInfo() method, to get underlines
64 // information of the current composition string. 71 // information of the current composition string.
65 void GetCompositionUnderlines( 72 void GetCompositionUnderlines(HIMC imm_context,
66 HIMC imm_context, 73 int target_start,
67 int target_start, 74 int target_end,
68 int target_end, 75 ui::CompositionUnderlines* underlines) {
69 std::vector<WebKit::WebCompositionUnderline>* underlines) {
70 int clause_size = ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE, 76 int clause_size = ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE,
71 NULL, 0); 77 NULL, 0);
72 int clause_length = clause_size / sizeof(uint32); 78 int clause_length = clause_size / sizeof(uint32);
73 if (clause_length) { 79 if (clause_length) {
74 scoped_array<uint32> clause_data(new uint32[clause_length]); 80 scoped_array<uint32> clause_data(new uint32[clause_length]);
75 if (clause_data.get()) { 81 if (clause_data.get()) {
76 ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE, 82 ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE,
77 clause_data.get(), clause_size); 83 clause_data.get(), clause_size);
78 for (int i = 0; i < clause_length - 1; ++i) { 84 for (int i = 0; i < clause_length - 1; ++i) {
79 WebKit::WebCompositionUnderline underline; 85 ui::CompositionUnderline underline;
80 underline.startOffset = clause_data[i]; 86 underline.start_offset = clause_data[i];
81 underline.endOffset = clause_data[i+1]; 87 underline.end_offset = clause_data[i+1];
82 underline.color = SK_ColorBLACK; 88 underline.color = SK_ColorBLACK;
83 underline.thick = false; 89 underline.thick = false;
84 90
85 // Use thick underline for the target clause. 91 // Use thick underline for the target clause.
86 if (underline.startOffset >= static_cast<unsigned>(target_start) && 92 if (underline.start_offset >= static_cast<unsigned>(target_start) &&
87 underline.endOffset <= static_cast<unsigned>(target_end)) { 93 underline.end_offset <= static_cast<unsigned>(target_end)) {
88 underline.thick = true; 94 underline.thick = true;
89 } 95 }
90 underlines->push_back(underline); 96 underlines->push_back(underline);
91 } 97 }
92 } 98 }
93 } 99 }
94 } 100 }
95 101
102 // Checks if a given primary language ID is a RTL language.
103 bool IsRTLPrimaryLangID(LANGID lang) {
104 switch (lang) {
105 case LANG_ARABIC:
106 case LANG_HEBREW:
107 case LANG_PERSIAN:
108 case LANG_SYRIAC:
109 case LANG_UIGHUR:
110 case LANG_URDU:
111 return true;
112 default:
113 return false;
114 }
115 }
116
96 } // namespace 117 } // namespace
97 118
119 namespace ui {
120
98 ImeInput::ImeInput() 121 ImeInput::ImeInput()
99 : ime_status_(false), 122 : ime_status_(false),
100 input_language_id_(LANG_USER_DEFAULT), 123 input_language_id_(LANG_USER_DEFAULT),
101 is_composing_(false), 124 is_composing_(false),
102 system_caret_(false), 125 system_caret_(false),
103 caret_rect_(-1, -1, 0, 0) { 126 caret_rect_(-1, -1, 0, 0) {
104 } 127 }
105 128
106 ImeInput::~ImeInput() { 129 ImeInput::~ImeInput() {
107 } 130 }
108 131
109 bool ImeInput::SetInputLanguage() { 132 bool ImeInput::SetInputLanguage() {
110 // Retrieve the current keyboard layout from Windows and determine whether 133 // Retrieve the current keyboard layout from Windows and determine whether
111 // or not the current input context has IMEs. 134 // or not the current input context has IMEs.
112 // Also save its input language for language-specific operations required 135 // Also save its input language for language-specific operations required
113 // while composing a text. 136 // while composing a text.
114 HKL keyboard_layout = ::GetKeyboardLayout(0); 137 HKL keyboard_layout = ::GetKeyboardLayout(0);
115 input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout); 138 input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout);
116 ime_status_ = (::ImmIsIME(keyboard_layout) == TRUE) ? true : false; 139 ime_status_ = (::ImmIsIME(keyboard_layout) == TRUE) ? true : false;
117 return ime_status_; 140 return ime_status_;
118 } 141 }
119 142
120
121 void ImeInput::CreateImeWindow(HWND window_handle) { 143 void ImeInput::CreateImeWindow(HWND window_handle) {
122 // When a user disables TSF (Text Service Framework) and CUAS (Cicero 144 // When a user disables TSF (Text Service Framework) and CUAS (Cicero
123 // Unaware Application Support), Chinese IMEs somehow ignore function calls 145 // Unaware Application Support), Chinese IMEs somehow ignore function calls
124 // to ::ImmSetCandidateWindow(), i.e. they do not move their candidate 146 // to ::ImmSetCandidateWindow(), i.e. they do not move their candidate
125 // window to the position given as its parameters, and use the position 147 // window to the position given as its parameters, and use the position
126 // of the current system caret instead, i.e. it uses ::GetCaretPos() to 148 // of the current system caret instead, i.e. it uses ::GetCaretPos() to
127 // retrieve the position of their IME candidate window. 149 // retrieve the position of their IME candidate window.
128 // Therefore, we create a temporary system caret for Chinese IMEs and use 150 // Therefore, we create a temporary system caret for Chinese IMEs and use
129 // it during this input context. 151 // it during this input context.
130 // Since some third-party Japanese IME also uses ::GetCaretPos() to determine 152 // Since some third-party Japanese IME also uses ::GetCaretPos() to determine
131 // their window position, we also create a caret for Japanese IMEs. 153 // their window position, we also create a caret for Japanese IMEs.
132 if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE || 154 if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
133 PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) { 155 PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
134 if (!system_caret_) { 156 if (!system_caret_) {
135 if (::CreateCaret(window_handle, NULL, 1, 1)) { 157 if (::CreateCaret(window_handle, NULL, 1, 1)) {
136 system_caret_ = true; 158 system_caret_ = true;
137 } 159 }
138 } 160 }
139 } 161 }
140 // Restore the positions of the IME windows. 162 // Restore the positions of the IME windows.
141 UpdateImeWindow(window_handle); 163 UpdateImeWindow(window_handle);
142 } 164 }
143 165
144 void ImeInput::SetImeWindowStyle(HWND window_handle, UINT message, 166 LRESULT ImeInput::SetImeWindowStyle(HWND window_handle, UINT message,
145 WPARAM wparam, LPARAM lparam, 167 WPARAM wparam, LPARAM lparam,
146 BOOL* handled) { 168 BOOL* handled) {
147 // To prevent the IMM (Input Method Manager) from displaying the IME 169 // To prevent the IMM (Input Method Manager) from displaying the IME
148 // composition window, Update the styles of the IME windows and EXPLICITLY 170 // composition window, Update the styles of the IME windows and EXPLICITLY
149 // call ::DefWindowProc() here. 171 // call ::DefWindowProc() here.
150 // NOTE(hbono): We can NEVER let WTL call ::DefWindowProc() when we update 172 // NOTE(hbono): We can NEVER let WTL call ::DefWindowProc() when we update
151 // the styles of IME windows because the 'lparam' variable is a local one 173 // the styles of IME windows because the 'lparam' variable is a local one
152 // and all its updates disappear in returning from this function, i.e. WTL 174 // and all its updates disappear in returning from this function, i.e. WTL
153 // does not call ::DefWindowProc() with our updated 'lparam' value but call 175 // does not call ::DefWindowProc() with our updated 'lparam' value but call
154 // the function with its original value and over-writes our window styles. 176 // the function with its original value and over-writes our window styles.
155 *handled = TRUE; 177 *handled = TRUE;
156 lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW; 178 lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
157 ::DefWindowProc(window_handle, message, wparam, lparam); 179 return ::DefWindowProc(window_handle, message, wparam, lparam);
158 } 180 }
159 181
160 void ImeInput::DestroyImeWindow(HWND window_handle) { 182 void ImeInput::DestroyImeWindow(HWND window_handle) {
161 // Destroy the system caret if we have created for this IME input context. 183 // Destroy the system caret if we have created for this IME input context.
162 if (system_caret_) { 184 if (system_caret_) {
163 ::DestroyCaret(); 185 ::DestroyCaret();
164 system_caret_ = false; 186 system_caret_ = false;
165 } 187 }
166 } 188 }
167 189
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 // We have to confirm there is an ongoing composition before completing it. 264 // We have to confirm there is an ongoing composition before completing it.
243 // This is for preventing some IMEs from getting confused while completing an 265 // This is for preventing some IMEs from getting confused while completing an
244 // ongoing composition even if they do not have any ongoing compositions.) 266 // ongoing composition even if they do not have any ongoing compositions.)
245 if (is_composing_) { 267 if (is_composing_) {
246 ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); 268 ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
247 ResetComposition(window_handle); 269 ResetComposition(window_handle);
248 } 270 }
249 } 271 }
250 272
251 void ImeInput::GetCompositionInfo(HIMC imm_context, LPARAM lparam, 273 void ImeInput::GetCompositionInfo(HIMC imm_context, LPARAM lparam,
252 ImeComposition* composition) { 274 CompositionText* composition) {
253 // We only care about GCS_COMPATTR, GCS_COMPCLAUSE and GCS_CURSORPOS, and 275 // We only care about GCS_COMPATTR, GCS_COMPCLAUSE and GCS_CURSORPOS, and
254 // convert them into underlines and selection range respectively. 276 // convert them into underlines and selection range respectively.
255 composition->underlines.clear(); 277 composition->underlines.clear();
256 278
257 int length = static_cast<int>(composition->ime_string.length()); 279 int length = static_cast<int>(composition->text.length());
280
281 // Find out the range selected by the user.
282 int target_start = length;
283 int target_end = length;
284 if (lparam & GCS_COMPATTR)
285 GetCompositionTargetRange(imm_context, &target_start, &target_end);
258 286
259 // Retrieve the selection range information. If CS_NOMOVECARET is specified, 287 // Retrieve the selection range information. If CS_NOMOVECARET is specified,
260 // that means the cursor should not be moved, then we just place the caret at 288 // that means the cursor should not be moved, then we just place the caret at
261 // the beginning of the composition string. Otherwise we should honour the 289 // the beginning of the composition string. Otherwise we should honour the
262 // GCS_CURSORPOS value if it's available. 290 // GCS_CURSORPOS value if it's available.
263 // TODO(suzhe): due to a bug of webkit, we currently can't use selection range 291 // TODO(suzhe): due to a bug of webkit, we currently can't use selection range
264 // with composition string. See: https://bugs.webkit.org/show_bug.cgi?id=40805 292 // with composition string. See: https://bugs.webkit.org/show_bug.cgi?id=40805
265 if (lparam & CS_NOMOVECARET) { 293 if (lparam & CS_NOMOVECARET) {
266 composition->selection_start = composition->selection_end = 0; 294 composition->selection = ui::Range(0);
267 } else if (lparam & GCS_CURSORPOS) { 295 } else if (lparam & GCS_CURSORPOS) {
268 composition->selection_start = composition->selection_end = 296 // If cursor position is same as target_start or target_end, then selects
269 ::ImmGetCompositionString(imm_context, GCS_CURSORPOS, NULL, 0); 297 // the target range instead. We always use cursor position as selection end,
298 // so that if the client doesn't support drawing selection with composition,
299 // it can always retrieve the correct cursor position.
300 int cursor = ::ImmGetCompositionString(imm_context, GCS_CURSORPOS, NULL, 0);
301 if (cursor == target_start)
302 composition->selection = ui::Range(target_end, cursor);
303 else if (cursor == target_end)
304 composition->selection = ui::Range(target_start, cursor);
305 else
306 composition->selection = ui::Range(cursor);
270 } else { 307 } else {
271 composition->selection_start = composition->selection_end = length; 308 composition->selection = ui::Range(target_start, target_end);
272 } 309 }
273 310
274 // Find out the range selected by the user.
275 int target_start = 0;
276 int target_end = 0;
277 if (lparam & GCS_COMPATTR)
278 GetCompositionTargetRange(imm_context, &target_start, &target_end);
279
280 // Retrieve the clause segmentations and convert them to underlines. 311 // Retrieve the clause segmentations and convert them to underlines.
281 if (lparam & GCS_COMPCLAUSE) { 312 if (lparam & GCS_COMPCLAUSE) {
282 GetCompositionUnderlines(imm_context, target_start, target_end, 313 GetCompositionUnderlines(imm_context, target_start, target_end,
283 &composition->underlines); 314 &composition->underlines);
284 } 315 }
285 316
286 // Set default underlines in case there is no clause information. 317 // Set default underlines in case there is no clause information.
287 if (!composition->underlines.size()) { 318 if (!composition->underlines.size()) {
288 WebKit::WebCompositionUnderline underline; 319 CompositionUnderline underline;
289 underline.color = SK_ColorBLACK; 320 underline.color = SK_ColorBLACK;
290 if (target_start > 0) { 321 if (target_start > 0) {
291 underline.startOffset = 0; 322 underline.start_offset = 0;
292 underline.endOffset = target_start; 323 underline.end_offset = target_start;
293 underline.thick = false; 324 underline.thick = false;
294 composition->underlines.push_back(underline); 325 composition->underlines.push_back(underline);
295 } 326 }
296 if (target_end > target_start) { 327 if (target_end > target_start) {
297 underline.startOffset = target_start; 328 underline.start_offset = target_start;
298 underline.endOffset = target_end; 329 underline.end_offset = target_end;
299 underline.thick = true; 330 underline.thick = true;
300 composition->underlines.push_back(underline); 331 composition->underlines.push_back(underline);
301 } 332 }
302 if (target_end < length) { 333 if (target_end < length) {
303 underline.startOffset = target_end; 334 underline.start_offset = target_end;
304 underline.endOffset = length; 335 underline.end_offset = length;
305 underline.thick = false; 336 underline.thick = false;
306 composition->underlines.push_back(underline); 337 composition->underlines.push_back(underline);
307 } 338 }
308 } 339 }
309 } 340 }
310 341
311 bool ImeInput::GetString(HIMC imm_context, WPARAM lparam, int type, 342 bool ImeInput::GetString(HIMC imm_context, WPARAM lparam, int type,
312 ImeComposition* composition) { 343 string16* result) {
313 bool result = false; 344 bool ret = false;
314 if (lparam & type) { 345 if (lparam & type) {
315 int string_size = ::ImmGetCompositionString(imm_context, type, NULL, 0); 346 int string_size = ::ImmGetCompositionString(imm_context, type, NULL, 0);
316 if (string_size > 0) { 347 if (string_size > 0) {
317 int string_length = string_size / sizeof(wchar_t); 348 int string_length = string_size / sizeof(wchar_t);
318 wchar_t *string_data = WriteInto(&composition->ime_string, 349 wchar_t *string_data = WriteInto(result, string_length + 1);
319 string_length + 1);
320 if (string_data) { 350 if (string_data) {
321 // Fill the given ImeComposition object. 351 // Fill the given result object.
322 ::ImmGetCompositionString(imm_context, type, 352 ::ImmGetCompositionString(imm_context, type, string_data, string_size);
323 string_data, string_size); 353 ret = true;
324 composition->string_type = type;
325 result = true;
326 } 354 }
327 } 355 }
328 } 356 }
329 return result; 357 return ret;
330 } 358 }
331 359
332 bool ImeInput::GetResult(HWND window_handle, LPARAM lparam, 360 bool ImeInput::GetResult(HWND window_handle, LPARAM lparam, string16* result) {
333 ImeComposition* composition) { 361 bool ret = false;
334 bool result = false;
335 HIMC imm_context = ::ImmGetContext(window_handle); 362 HIMC imm_context = ::ImmGetContext(window_handle);
336 if (imm_context) { 363 if (imm_context) {
337 // Copy the result string to the ImeComposition object. 364 ret = GetString(imm_context, lparam, GCS_RESULTSTR, result);
338 result = GetString(imm_context, lparam, GCS_RESULTSTR, composition);
339 // Reset all the other parameters because a result string does not
340 // have composition attributes.
341 composition->selection_start = 0;
342 composition->selection_end = 0;
343 ::ImmReleaseContext(window_handle, imm_context); 365 ::ImmReleaseContext(window_handle, imm_context);
344 } 366 }
345 return result; 367 return ret;
346 } 368 }
347 369
348 bool ImeInput::GetComposition(HWND window_handle, LPARAM lparam, 370 bool ImeInput::GetComposition(HWND window_handle, LPARAM lparam,
349 ImeComposition* composition) { 371 CompositionText* composition) {
350 bool result = false; 372 bool ret = false;
351 HIMC imm_context = ::ImmGetContext(window_handle); 373 HIMC imm_context = ::ImmGetContext(window_handle);
352 if (imm_context) { 374 if (imm_context) {
353 // Copy the composition string to the ImeComposition object. 375 // Copy the composition string to the CompositionText object.
354 result = GetString(imm_context, lparam, GCS_COMPSTR, composition); 376 ret = GetString(imm_context, lparam, GCS_COMPSTR, &composition->text);
355 377
356 // This is a dirty workaround for facebook. Facebook deletes the placeholder 378 if (ret) {
357 // character (U+3000) used by Traditional-Chinese IMEs at the beginning of 379 // This is a dirty workaround for facebook. Facebook deletes the
358 // composition text. This prevents WebKit from replacing this placeholder 380 // placeholder character (U+3000) used by Traditional-Chinese IMEs at the
359 // character with a Traditional-Chinese character, i.e. we cannot input any 381 // beginning of composition text. This prevents WebKit from replacing this
360 // characters in a comment box of facebook with Traditional-Chinese IMEs. 382 // placeholder character with a Traditional-Chinese character, i.e. we
361 // As a workaround, we replace U+3000 at the beginning of composition text 383 // cannot input any characters in a comment box of facebook with
362 // with U+FF3F, a placeholder character used by Japanese IMEs. 384 // Traditional-Chinese IMEs. As a workaround, we replace U+3000 at the
363 if (input_language_id_ == MAKELANGID(LANG_CHINESE, 385 // beginning of composition text with U+FF3F, a placeholder character used
364 SUBLANG_CHINESE_TRADITIONAL) && 386 // by Japanese IMEs.
365 composition->ime_string[0] == 0x3000) { 387 if (input_language_id_ == MAKELANGID(LANG_CHINESE,
366 composition->ime_string[0] = 0xFF3F; 388 SUBLANG_CHINESE_TRADITIONAL) &&
389 composition->text[0] == 0x3000) {
390 composition->text[0] = 0xFF3F;
391 }
392
393 // Retrieve the composition underlines and selection range information.
394 GetCompositionInfo(imm_context, lparam, composition);
395
396 // Mark that there is an ongoing composition.
397 is_composing_ = true;
367 } 398 }
368 399
369 // Retrieve the composition underlines and selection range information.
370 GetCompositionInfo(imm_context, lparam, composition);
371
372 // Mark that there is an ongoing composition.
373 is_composing_ = true;
374
375 ::ImmReleaseContext(window_handle, imm_context); 400 ::ImmReleaseContext(window_handle, imm_context);
376 } 401 }
377 return result; 402 return ret;
378 } 403 }
379 404
380 void ImeInput::DisableIME(HWND window_handle) { 405 void ImeInput::DisableIME(HWND window_handle) {
381 // A renderer process have moved its input focus to a password input 406 // A renderer process have moved its input focus to a password input
382 // when there is an ongoing composition, e.g. a user has clicked a 407 // when there is an ongoing composition, e.g. a user has clicked a
383 // mouse button and selected a password input while composing a text. 408 // mouse button and selected a password input while composing a text.
384 // For this case, we have to complete the ongoing composition and 409 // For this case, we have to complete the ongoing composition and
385 // clean up the resources attached to this object BEFORE DISABLING THE IME. 410 // clean up the resources attached to this object BEFORE DISABLING THE IME.
386 CleanupComposition(window_handle); 411 CleanupComposition(window_handle);
387 ::ImmAssociateContextEx(window_handle, NULL, 0); 412 ::ImmAssociateContextEx(window_handle, NULL, 0);
(...skipping 26 matching lines...) Expand all
414 if (caret_rect_ != caret_rect) { 439 if (caret_rect_ != caret_rect) {
415 caret_rect_ = caret_rect; 440 caret_rect_ = caret_rect;
416 // Move the IME windows. 441 // Move the IME windows.
417 HIMC imm_context = ::ImmGetContext(window_handle); 442 HIMC imm_context = ::ImmGetContext(window_handle);
418 if (imm_context) { 443 if (imm_context) {
419 MoveImeWindow(window_handle, imm_context); 444 MoveImeWindow(window_handle, imm_context);
420 ::ImmReleaseContext(window_handle, imm_context); 445 ::ImmReleaseContext(window_handle, imm_context);
421 } 446 }
422 } 447 }
423 } 448 }
449
450 std::string ImeInput::GetInputLanguageName() const {
451 const LCID locale_id = MAKELCID(input_language_id_, SORT_DEFAULT);
452 // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9.
453 wchar_t buffer[9];
454
455 // Get language id.
456 int length = ::GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &buffer[0],
457 arraysize(buffer));
458 if (length <= 1)
459 return std::string();
460
461 std::string language;
462 WideToUTF8(buffer, length - 1, &language);
463 if (SUBLANGID(input_language_id_) == SUBLANG_NEUTRAL)
464 return language;
465
466 // Get region id.
467 length = ::GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &buffer[0],
468 arraysize(buffer));
469 if (length <= 1)
470 return language;
471
472 std::string region;
473 WideToUTF8(buffer, length - 1, &region);
474 return language.append(1, '-').append(region);
475 }
476
477 base::i18n::TextDirection ImeInput::GetTextDirection() const {
478 return IsRTLPrimaryLangID(PRIMARYLANGID(input_language_id_)) ?
479 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
480 }
481
482 // static
483 bool ImeInput::IsRTLKeyboardLayoutInstalled() {
484 static enum {
485 RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED,
486 RTL_KEYBOARD_LAYOUT_INSTALLED,
487 RTL_KEYBOARD_LAYOUT_NOT_INSTALLED,
488 RTL_KEYBOARD_LAYOUT_ERROR,
489 } layout = RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED;
490
491 // Cache the result value.
492 if (layout != RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED)
493 return layout == RTL_KEYBOARD_LAYOUT_INSTALLED;
494
495 // Retrieve the number of layouts installed in this system.
496 int size = GetKeyboardLayoutList(0, NULL);
497 if (size <= 0) {
498 layout = RTL_KEYBOARD_LAYOUT_ERROR;
499 return false;
500 }
501
502 // Retrieve the keyboard layouts in an array and check if there is an RTL
503 // layout in it.
504 scoped_array<HKL> layouts(new HKL[size]);
505 ::GetKeyboardLayoutList(size, layouts.get());
506 for (int i = 0; i < size; ++i) {
507 if (IsRTLPrimaryLangID(PRIMARYLANGID(layouts[i]))) {
508 layout = RTL_KEYBOARD_LAYOUT_INSTALLED;
509 return true;
510 }
511 }
512
513 layout = RTL_KEYBOARD_LAYOUT_NOT_INSTALLED;
514 return false;
515 }
516
517 bool ImeInput::IsCtrlShiftPressed(base::i18n::TextDirection* direction) {
518 uint8_t keystate[256];
519 if (!::GetKeyboardState(&keystate[0]))
520 return false;
521
522 // To check if a user is pressing only a control key and a right-shift key
523 // (or a left-shift key), we use the steps below:
524 // 1. Check if a user is pressing a control key and a right-shift key (or
525 // a left-shift key).
526 // 2. If the condition 1 is true, we should check if there are any other
527 // keys pressed at the same time.
528 // To ignore the keys checked in 1, we set their status to 0 before
529 // checking the key status.
530 const int kKeyDownMask = 0x80;
531 if ((keystate[VK_CONTROL] & kKeyDownMask) == 0)
532 return false;
533
534 if (keystate[VK_RSHIFT] & kKeyDownMask) {
535 keystate[VK_RSHIFT] = 0;
536 *direction = base::i18n::RIGHT_TO_LEFT;
537 } else if (keystate[VK_LSHIFT] & kKeyDownMask) {
538 keystate[VK_LSHIFT] = 0;
539 *direction = base::i18n::LEFT_TO_RIGHT;
540 } else {
541 return false;
542 }
543
544 // Scan the key status to find pressed keys. We should adandon changing the
545 // text direction when there are other pressed keys.
546 // This code is executed only when a user is pressing a control key and a
547 // right-shift key (or a left-shift key), i.e. we should ignore the status of
548 // the keys: VK_SHIFT, VK_CONTROL, VK_RCONTROL, and VK_LCONTROL.
549 // So, we reset their status to 0 and ignore them.
550 keystate[VK_SHIFT] = 0;
551 keystate[VK_CONTROL] = 0;
552 keystate[VK_RCONTROL] = 0;
553 keystate[VK_LCONTROL] = 0;
554 for (int i = 0; i <= VK_PACKET; ++i) {
555 if (keystate[i] & kKeyDownMask)
556 return false;
557 }
558 return true;
559 }
560
561 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/win/ime_input.h ('k') | ui/ui_base.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698