| Index: ui/base/ime/win/imm32_manager.cc
|
| diff --git a/ui/base/ime/win/imm32_manager.cc b/ui/base/ime/win/imm32_manager.cc
|
| deleted file mode 100644
|
| index 7ad2d875e4c881b75387ee87d47698d859131e14..0000000000000000000000000000000000000000
|
| --- a/ui/base/ime/win/imm32_manager.cc
|
| +++ /dev/null
|
| @@ -1,642 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "ui/base/ime/win/imm32_manager.h"
|
| -
|
| -#include <msctf.h>
|
| -
|
| -#include "base/basictypes.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/strings/string16.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "base/win/scoped_comptr.h"
|
| -#include "third_party/skia/include/core/SkColor.h"
|
| -#include "ui/base/ime/composition_text.h"
|
| -
|
| -// "imm32.lib" is required by IMM32 APIs used in this file.
|
| -// NOTE(hbono): To comply with a comment from Darin, I have added
|
| -// this #pragma directive instead of adding "imm32.lib" to a project file.
|
| -#pragma comment(lib, "imm32.lib")
|
| -
|
| -// Following code requires wchar_t to be same as char16. It should always be
|
| -// true on Windows.
|
| -COMPILE_ASSERT(sizeof(wchar_t) == sizeof(base::char16), wchar_t__char16_diff);
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// IMM32Manager
|
| -
|
| -namespace {
|
| -
|
| -// Determines whether or not the given attribute represents a target
|
| -// (a.k.a. a selection).
|
| -bool IsTargetAttribute(char attribute) {
|
| - return (attribute == ATTR_TARGET_CONVERTED ||
|
| - attribute == ATTR_TARGET_NOTCONVERTED);
|
| -}
|
| -
|
| -// Helper function for IMM32Manager::GetCompositionInfo() method, to get the
|
| -// target range that's selected by the user in the current composition string.
|
| -void GetCompositionTargetRange(HIMC imm_context, int* target_start,
|
| - int* target_end) {
|
| - int attribute_size = ::ImmGetCompositionString(imm_context, GCS_COMPATTR,
|
| - NULL, 0);
|
| - if (attribute_size > 0) {
|
| - int start = 0;
|
| - int end = 0;
|
| - scoped_ptr<char[]> attribute_data(new char[attribute_size]);
|
| - if (attribute_data.get()) {
|
| - ::ImmGetCompositionString(imm_context, GCS_COMPATTR,
|
| - attribute_data.get(), attribute_size);
|
| - for (start = 0; start < attribute_size; ++start) {
|
| - if (IsTargetAttribute(attribute_data[start]))
|
| - break;
|
| - }
|
| - for (end = start; end < attribute_size; ++end) {
|
| - if (!IsTargetAttribute(attribute_data[end]))
|
| - break;
|
| - }
|
| - }
|
| - *target_start = start;
|
| - *target_end = end;
|
| - }
|
| -}
|
| -
|
| -// Helper function for IMM32Manager::GetCompositionInfo() method, to get
|
| -// underlines information of the current composition string.
|
| -void GetCompositionUnderlines(HIMC imm_context,
|
| - int target_start,
|
| - int target_end,
|
| - ui::CompositionUnderlines* underlines) {
|
| - int clause_size = ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE,
|
| - NULL, 0);
|
| - int clause_length = clause_size / sizeof(uint32);
|
| - if (clause_length) {
|
| - scoped_ptr<uint32[]> clause_data(new uint32[clause_length]);
|
| - if (clause_data.get()) {
|
| - ::ImmGetCompositionString(imm_context, GCS_COMPCLAUSE,
|
| - clause_data.get(), clause_size);
|
| - for (int i = 0; i < clause_length - 1; ++i) {
|
| - ui::CompositionUnderline underline;
|
| - underline.start_offset = clause_data[i];
|
| - underline.end_offset = clause_data[i+1];
|
| - underline.color = SK_ColorBLACK;
|
| - underline.thick = false;
|
| - underline.background_color = SK_ColorTRANSPARENT;
|
| -
|
| - // Use thick underline for the target clause.
|
| - if (underline.start_offset >= static_cast<uint32>(target_start) &&
|
| - underline.end_offset <= static_cast<uint32>(target_end)) {
|
| - underline.thick = true;
|
| - }
|
| - underlines->push_back(underline);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -// Checks if a given primary language ID is a RTL language.
|
| -bool IsRTLPrimaryLangID(LANGID lang) {
|
| - switch (lang) {
|
| - case LANG_ARABIC:
|
| - case LANG_HEBREW:
|
| - case LANG_PERSIAN:
|
| - case LANG_SYRIAC:
|
| - case LANG_UIGHUR:
|
| - case LANG_URDU:
|
| - return true;
|
| - default:
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace ui {
|
| -
|
| -IMM32Manager::IMM32Manager()
|
| - : ime_status_(false),
|
| - input_language_id_(LANG_USER_DEFAULT),
|
| - is_composing_(false),
|
| - system_caret_(false),
|
| - caret_rect_(-1, -1, 0, 0),
|
| - use_composition_window_(false) {
|
| -}
|
| -
|
| -IMM32Manager::~IMM32Manager() {
|
| -}
|
| -
|
| -bool IMM32Manager::SetInputLanguage() {
|
| - // Retrieve the current keyboard layout from Windows and determine whether
|
| - // or not the current input context has IMEs.
|
| - // Also save its input language for language-specific operations required
|
| - // while composing a text.
|
| - HKL keyboard_layout = ::GetKeyboardLayout(0);
|
| - input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout);
|
| -
|
| - // Check TSF Input Processor first.
|
| - // If the active profile is TSF INPUTPROCESSOR, this is IME.
|
| - base::win::ScopedComPtr<ITfInputProcessorProfileMgr> prof_mgr;
|
| - TF_INPUTPROCESSORPROFILE prof;
|
| - if (SUCCEEDED(prof_mgr.CreateInstance(CLSID_TF_InputProcessorProfiles)) &&
|
| - SUCCEEDED(prof_mgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &prof)) &&
|
| - prof.hkl == NULL &&
|
| - prof.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR) {
|
| - ime_status_ = true;
|
| - } else {
|
| - // If the curent language is not using TSF, check IMM32 based IMEs.
|
| - // As ImmIsIME always returns non-0 value on Vista+, use ImmGetIMEFileName
|
| - // instead to check if this HKL has any associated IME file.
|
| - ime_status_ = (ImmGetIMEFileName(keyboard_layout, NULL, 0) != 0);
|
| - }
|
| -
|
| - return ime_status_;
|
| -}
|
| -
|
| -void IMM32Manager::CreateImeWindow(HWND window_handle) {
|
| - // When a user disables TSF (Text Service Framework) and CUAS (Cicero
|
| - // Unaware Application Support), Chinese IMEs somehow ignore function calls
|
| - // to ::ImmSetCandidateWindow(), i.e. they do not move their candidate
|
| - // window to the position given as its parameters, and use the position
|
| - // of the current system caret instead, i.e. it uses ::GetCaretPos() to
|
| - // retrieve the position of their IME candidate window.
|
| - // Therefore, we create a temporary system caret for Chinese IMEs and use
|
| - // it during this input context.
|
| - // Since some third-party Japanese IME also uses ::GetCaretPos() to determine
|
| - // their window position, we also create a caret for Japanese IMEs.
|
| - if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
|
| - PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
|
| - if (!system_caret_) {
|
| - if (::CreateCaret(window_handle, NULL, 1, 1)) {
|
| - system_caret_ = true;
|
| - }
|
| - }
|
| - }
|
| - // Restore the positions of the IME windows.
|
| - UpdateImeWindow(window_handle);
|
| -}
|
| -
|
| -LRESULT IMM32Manager::SetImeWindowStyle(HWND window_handle, UINT message,
|
| - WPARAM wparam, LPARAM lparam,
|
| - BOOL* handled) {
|
| - // To prevent the IMM (Input Method Manager) from displaying the IME
|
| - // composition window, Update the styles of the IME windows and EXPLICITLY
|
| - // call ::DefWindowProc() here.
|
| - // NOTE(hbono): We can NEVER let WTL call ::DefWindowProc() when we update
|
| - // the styles of IME windows because the 'lparam' variable is a local one
|
| - // and all its updates disappear in returning from this function, i.e. WTL
|
| - // does not call ::DefWindowProc() with our updated 'lparam' value but call
|
| - // the function with its original value and over-writes our window styles.
|
| - *handled = TRUE;
|
| - lparam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
|
| - return ::DefWindowProc(window_handle, message, wparam, lparam);
|
| -}
|
| -
|
| -void IMM32Manager::DestroyImeWindow(HWND window_handle) {
|
| - // Destroy the system caret if we have created for this IME input context.
|
| - if (system_caret_) {
|
| - ::DestroyCaret();
|
| - system_caret_ = false;
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::MoveImeWindow(HWND window_handle, HIMC imm_context) {
|
| - // Does nothing when the target window has no input focus. This is important
|
| - // because the renderer may issue SelectionBoundsChanged event even when it
|
| - // has no input focus. (e.g. the page update caused by incremental search.)
|
| - // So this event should be ignored when the |window_handle| no longer has the
|
| - // input focus.
|
| - if (GetFocus() != window_handle)
|
| - return;
|
| -
|
| - int x = caret_rect_.x();
|
| - int y = caret_rect_.y();
|
| -
|
| - const int kCaretMargin = 1;
|
| - if (!use_composition_window_ &&
|
| - PRIMARYLANGID(input_language_id_) == LANG_CHINESE) {
|
| - // As written in a comment in IMM32Manager::CreateImeWindow(),
|
| - // Chinese IMEs ignore function calls to ::ImmSetCandidateWindow()
|
| - // when a user disables TSF (Text Service Framework) and CUAS (Cicero
|
| - // Unaware Application Support).
|
| - // On the other hand, when a user enables TSF and CUAS, Chinese IMEs
|
| - // ignore the position of the current system caret and uses the
|
| - // parameters given to ::ImmSetCandidateWindow() with its 'dwStyle'
|
| - // parameter CFS_CANDIDATEPOS.
|
| - // Therefore, we do not only call ::ImmSetCandidateWindow() but also
|
| - // set the positions of the temporary system caret if it exists.
|
| - CANDIDATEFORM candidate_position = {0, CFS_CANDIDATEPOS, {x, y},
|
| - {0, 0, 0, 0}};
|
| - ::ImmSetCandidateWindow(imm_context, &candidate_position);
|
| - }
|
| - if (system_caret_) {
|
| - switch (PRIMARYLANGID(input_language_id_)) {
|
| - case LANG_JAPANESE:
|
| - ::SetCaretPos(x, y + caret_rect_.height());
|
| - break;
|
| - default:
|
| - ::SetCaretPos(x, y);
|
| - break;
|
| - }
|
| - }
|
| - if (use_composition_window_) {
|
| - // Moves the composition text window.
|
| - COMPOSITIONFORM cf = {CFS_POINT, {x, y}};
|
| - ::ImmSetCompositionWindow(imm_context, &cf);
|
| - // Don't need to set the position of candidate window.
|
| - return;
|
| - }
|
| -
|
| - if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) {
|
| - // Chinese IMEs and Japanese IMEs require the upper-left corner of
|
| - // the caret to move the position of their candidate windows.
|
| - // On the other hand, Korean IMEs require the lower-left corner of the
|
| - // caret to move their candidate windows.
|
| - y += kCaretMargin;
|
| - }
|
| - // Japanese IMEs and Korean IMEs also use the rectangle given to
|
| - // ::ImmSetCandidateWindow() with its 'dwStyle' parameter CFS_EXCLUDE
|
| - // to move their candidate windows when a user disables TSF and CUAS.
|
| - // Therefore, we also set this parameter here.
|
| - CANDIDATEFORM exclude_rectangle = {0, CFS_EXCLUDE, {x, y},
|
| - {x, y, x + caret_rect_.width(), y + caret_rect_.height()}};
|
| - ::ImmSetCandidateWindow(imm_context, &exclude_rectangle);
|
| -}
|
| -
|
| -void IMM32Manager::UpdateImeWindow(HWND window_handle) {
|
| - // Just move the IME window attached to the given window.
|
| - if (caret_rect_.x() >= 0 && caret_rect_.y() >= 0) {
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - MoveImeWindow(window_handle, imm_context);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::CleanupComposition(HWND window_handle) {
|
| - // Notify the IMM attached to the given window to complete the ongoing
|
| - // composition, (this case happens when the given window is de-activated
|
| - // while composing a text and re-activated), and reset the omposition status.
|
| - if (is_composing_) {
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - ResetComposition(window_handle);
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::ResetComposition(HWND window_handle) {
|
| - // Currently, just reset the composition status.
|
| - is_composing_ = false;
|
| -}
|
| -
|
| -void IMM32Manager::CompleteComposition(HWND window_handle, HIMC imm_context) {
|
| - // We have to confirm there is an ongoing composition before completing it.
|
| - // This is for preventing some IMEs from getting confused while completing an
|
| - // ongoing composition even if they do not have any ongoing compositions.)
|
| - if (is_composing_) {
|
| - ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
|
| - ResetComposition(window_handle);
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::GetCompositionInfo(HIMC imm_context, LPARAM lparam,
|
| - CompositionText* composition) {
|
| - // We only care about GCS_COMPATTR, GCS_COMPCLAUSE and GCS_CURSORPOS, and
|
| - // convert them into underlines and selection range respectively.
|
| - composition->underlines.clear();
|
| -
|
| - int length = static_cast<int>(composition->text.length());
|
| -
|
| - // Find out the range selected by the user.
|
| - int target_start = length;
|
| - int target_end = length;
|
| - if (lparam & GCS_COMPATTR)
|
| - GetCompositionTargetRange(imm_context, &target_start, &target_end);
|
| -
|
| - // Retrieve the selection range information. If CS_NOMOVECARET is specified,
|
| - // that means the cursor should not be moved, then we just place the caret at
|
| - // the beginning of the composition string. Otherwise we should honour the
|
| - // GCS_CURSORPOS value if it's available.
|
| - // TODO(suzhe): due to a bug of webkit, we currently can't use selection range
|
| - // with composition string. See: https://bugs.webkit.org/show_bug.cgi?id=40805
|
| - if (!(lparam & CS_NOMOVECARET) && (lparam & GCS_CURSORPOS)) {
|
| - // IMM32 does not support non-zero-width selection in a composition. So
|
| - // always use the caret position as selection range.
|
| - int cursor = ::ImmGetCompositionString(imm_context, GCS_CURSORPOS, NULL, 0);
|
| - composition->selection = gfx::Range(cursor);
|
| - } else {
|
| - composition->selection = gfx::Range(0);
|
| - }
|
| -
|
| - // Retrieve the clause segmentations and convert them to underlines.
|
| - if (lparam & GCS_COMPCLAUSE) {
|
| - GetCompositionUnderlines(imm_context, target_start, target_end,
|
| - &composition->underlines);
|
| - }
|
| -
|
| - // Set default underlines in case there is no clause information.
|
| - if (!composition->underlines.size()) {
|
| - CompositionUnderline underline;
|
| - underline.color = SK_ColorBLACK;
|
| - underline.background_color = SK_ColorTRANSPARENT;
|
| - if (target_start > 0) {
|
| - underline.start_offset = 0U;
|
| - underline.end_offset = static_cast<uint32>(target_start);
|
| - underline.thick = false;
|
| - composition->underlines.push_back(underline);
|
| - }
|
| - if (target_end > target_start) {
|
| - underline.start_offset = static_cast<uint32>(target_start);
|
| - underline.end_offset = static_cast<uint32>(target_end);
|
| - underline.thick = true;
|
| - composition->underlines.push_back(underline);
|
| - }
|
| - if (target_end < length) {
|
| - underline.start_offset = static_cast<uint32>(target_end);
|
| - underline.end_offset = static_cast<uint32>(length);
|
| - underline.thick = false;
|
| - composition->underlines.push_back(underline);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool IMM32Manager::GetString(HIMC imm_context,
|
| - WPARAM lparam,
|
| - int type,
|
| - base::string16* result) {
|
| - if (!(lparam & type))
|
| - return false;
|
| - LONG string_size = ::ImmGetCompositionString(imm_context, type, NULL, 0);
|
| - if (string_size <= 0)
|
| - return false;
|
| - DCHECK_EQ(0u, string_size % sizeof(wchar_t));
|
| - ::ImmGetCompositionString(imm_context, type,
|
| - WriteInto(result, (string_size / sizeof(wchar_t)) + 1), string_size);
|
| - return true;
|
| -}
|
| -
|
| -bool IMM32Manager::GetResult(
|
| - HWND window_handle, LPARAM lparam, base::string16* result) {
|
| - bool ret = false;
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - ret = GetString(imm_context, lparam, GCS_RESULTSTR, result);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| -bool IMM32Manager::GetComposition(HWND window_handle, LPARAM lparam,
|
| - CompositionText* composition) {
|
| - bool ret = false;
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - // Copy the composition string to the CompositionText object.
|
| - ret = GetString(imm_context, lparam, GCS_COMPSTR, &composition->text);
|
| -
|
| - if (ret) {
|
| - // This is a dirty workaround for facebook. Facebook deletes the
|
| - // placeholder character (U+3000) used by Traditional-Chinese IMEs at the
|
| - // beginning of composition text. This prevents WebKit from replacing this
|
| - // placeholder character with a Traditional-Chinese character, i.e. we
|
| - // cannot input any characters in a comment box of facebook with
|
| - // Traditional-Chinese IMEs. As a workaround, we replace U+3000 at the
|
| - // beginning of composition text with U+FF3F, a placeholder character used
|
| - // by Japanese IMEs.
|
| - if (input_language_id_ == MAKELANGID(LANG_CHINESE,
|
| - SUBLANG_CHINESE_TRADITIONAL) &&
|
| - composition->text[0] == 0x3000) {
|
| - composition->text[0] = 0xFF3F;
|
| - }
|
| -
|
| - // Retrieve the composition underlines and selection range information.
|
| - GetCompositionInfo(imm_context, lparam, composition);
|
| -
|
| - // Mark that there is an ongoing composition.
|
| - is_composing_ = true;
|
| - }
|
| -
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - return ret;
|
| -}
|
| -
|
| -void IMM32Manager::DisableIME(HWND window_handle) {
|
| - // A renderer process have moved its input focus to a password input
|
| - // when there is an ongoing composition, e.g. a user has clicked a
|
| - // mouse button and selected a password input while composing a text.
|
| - // For this case, we have to complete the ongoing composition and
|
| - // clean up the resources attached to this object BEFORE DISABLING THE IME.
|
| - CleanupComposition(window_handle);
|
| - ::ImmAssociateContextEx(window_handle, NULL, 0);
|
| -}
|
| -
|
| -void IMM32Manager::CancelIME(HWND window_handle) {
|
| - if (is_composing_) {
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - ::ImmNotifyIME(imm_context, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - ResetComposition(window_handle);
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::EnableIME(HWND window_handle) {
|
| - // Load the default IME context.
|
| - // NOTE(hbono)
|
| - // IMM ignores this call if the IME context is loaded. Therefore, we do
|
| - // not have to check whether or not the IME context is loaded.
|
| - ::ImmAssociateContextEx(window_handle, NULL, IACE_DEFAULT);
|
| -}
|
| -
|
| -void IMM32Manager::UpdateCaretRect(HWND window_handle,
|
| - const gfx::Rect& caret_rect) {
|
| - // Save the caret position, and Update the position of the IME window.
|
| - // This update is used for moving an IME window when a renderer process
|
| - // resize/moves the input caret.
|
| - if (caret_rect_ != caret_rect) {
|
| - caret_rect_ = caret_rect;
|
| - // Move the IME windows.
|
| - HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (imm_context) {
|
| - MoveImeWindow(window_handle, imm_context);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void IMM32Manager::SetUseCompositionWindow(bool use_composition_window) {
|
| - use_composition_window_ = use_composition_window;
|
| -}
|
| -
|
| -std::string IMM32Manager::GetInputLanguageName() const {
|
| - const LCID locale_id = MAKELCID(input_language_id_, SORT_DEFAULT);
|
| - // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9.
|
| - wchar_t buffer[9];
|
| -
|
| - // Get language id.
|
| - int length = ::GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &buffer[0],
|
| - arraysize(buffer));
|
| - if (length <= 1)
|
| - return std::string();
|
| -
|
| - std::string language;
|
| - base::WideToUTF8(buffer, length - 1, &language);
|
| - if (SUBLANGID(input_language_id_) == SUBLANG_NEUTRAL)
|
| - return language;
|
| -
|
| - // Get region id.
|
| - length = ::GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &buffer[0],
|
| - arraysize(buffer));
|
| - if (length <= 1)
|
| - return language;
|
| -
|
| - std::string region;
|
| - base::WideToUTF8(buffer, length - 1, ®ion);
|
| - return language.append(1, '-').append(region);
|
| -}
|
| -
|
| -void IMM32Manager::SetTextInputMode(HWND window_handle,
|
| - TextInputMode input_mode) {
|
| - if (input_mode == ui::TEXT_INPUT_MODE_DEFAULT)
|
| - return;
|
| -
|
| - const HIMC imm_context = ::ImmGetContext(window_handle);
|
| - if (!imm_context)
|
| - return;
|
| -
|
| - DWORD conversion_mode = 0;
|
| - DWORD sentence_mode = 0;
|
| - if (::ImmGetConversionStatus(imm_context, &conversion_mode, &sentence_mode)
|
| - == FALSE) {
|
| - return;
|
| - }
|
| -
|
| - BOOL open = FALSE;
|
| - ConvertInputModeToImmFlags(input_mode, conversion_mode, &open,
|
| - &conversion_mode),
|
| -
|
| - ::ImmSetOpenStatus(imm_context, open);
|
| - if (open)
|
| - ::ImmSetConversionStatus(imm_context, conversion_mode, sentence_mode);
|
| - ::ImmReleaseContext(window_handle, imm_context);
|
| -}
|
| -
|
| -// static
|
| -bool IMM32Manager::IsRTLKeyboardLayoutInstalled() {
|
| - static enum {
|
| - RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED,
|
| - RTL_KEYBOARD_LAYOUT_INSTALLED,
|
| - RTL_KEYBOARD_LAYOUT_NOT_INSTALLED,
|
| - RTL_KEYBOARD_LAYOUT_ERROR,
|
| - } layout = RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED;
|
| -
|
| - // Cache the result value.
|
| - if (layout != RTL_KEYBOARD_LAYOUT_NOT_INITIALIZED)
|
| - return layout == RTL_KEYBOARD_LAYOUT_INSTALLED;
|
| -
|
| - // Retrieve the number of layouts installed in this system.
|
| - int size = GetKeyboardLayoutList(0, NULL);
|
| - if (size <= 0) {
|
| - layout = RTL_KEYBOARD_LAYOUT_ERROR;
|
| - return false;
|
| - }
|
| -
|
| - // Retrieve the keyboard layouts in an array and check if there is an RTL
|
| - // layout in it.
|
| - scoped_ptr<HKL[]> layouts(new HKL[size]);
|
| - ::GetKeyboardLayoutList(size, layouts.get());
|
| - for (int i = 0; i < size; ++i) {
|
| - if (IsRTLPrimaryLangID(PRIMARYLANGID(layouts[i]))) {
|
| - layout = RTL_KEYBOARD_LAYOUT_INSTALLED;
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - layout = RTL_KEYBOARD_LAYOUT_NOT_INSTALLED;
|
| - return false;
|
| -}
|
| -
|
| -bool IMM32Manager::IsCtrlShiftPressed(base::i18n::TextDirection* direction) {
|
| - uint8_t keystate[256];
|
| - if (!::GetKeyboardState(&keystate[0]))
|
| - return false;
|
| -
|
| - // To check if a user is pressing only a control key and a right-shift key
|
| - // (or a left-shift key), we use the steps below:
|
| - // 1. Check if a user is pressing a control key and a right-shift key (or
|
| - // a left-shift key).
|
| - // 2. If the condition 1 is true, we should check if there are any other
|
| - // keys pressed at the same time.
|
| - // To ignore the keys checked in 1, we set their status to 0 before
|
| - // checking the key status.
|
| - const int kKeyDownMask = 0x80;
|
| - if ((keystate[VK_CONTROL] & kKeyDownMask) == 0)
|
| - return false;
|
| -
|
| - if (keystate[VK_RSHIFT] & kKeyDownMask) {
|
| - keystate[VK_RSHIFT] = 0;
|
| - *direction = base::i18n::RIGHT_TO_LEFT;
|
| - } else if (keystate[VK_LSHIFT] & kKeyDownMask) {
|
| - keystate[VK_LSHIFT] = 0;
|
| - *direction = base::i18n::LEFT_TO_RIGHT;
|
| - } else {
|
| - return false;
|
| - }
|
| -
|
| - // Scan the key status to find pressed keys. We should abandon changing the
|
| - // text direction when there are other pressed keys.
|
| - // This code is executed only when a user is pressing a control key and a
|
| - // right-shift key (or a left-shift key), i.e. we should ignore the status of
|
| - // the keys: VK_SHIFT, VK_CONTROL, VK_RCONTROL, and VK_LCONTROL.
|
| - // So, we reset their status to 0 and ignore them.
|
| - keystate[VK_SHIFT] = 0;
|
| - keystate[VK_CONTROL] = 0;
|
| - keystate[VK_RCONTROL] = 0;
|
| - keystate[VK_LCONTROL] = 0;
|
| - // Oddly, pressing F10 in another application seemingly breaks all subsequent
|
| - // calls to GetKeyboardState regarding the state of the F22 key. Perhaps this
|
| - // defect is limited to my keyboard driver, but ignoring F22 should be okay.
|
| - keystate[VK_F22] = 0;
|
| - for (int i = 0; i <= VK_PACKET; ++i) {
|
| - if (keystate[i] & kKeyDownMask)
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void IMM32Manager::ConvertInputModeToImmFlags(TextInputMode input_mode,
|
| - DWORD initial_conversion_mode,
|
| - BOOL* open,
|
| - DWORD* new_conversion_mode) {
|
| - *open = TRUE;
|
| - *new_conversion_mode = initial_conversion_mode;
|
| - switch (input_mode) {
|
| - case ui::TEXT_INPUT_MODE_FULL_WIDTH_LATIN:
|
| - *new_conversion_mode |= IME_CMODE_FULLSHAPE;
|
| - *new_conversion_mode &= ~(IME_CMODE_NATIVE
|
| - | IME_CMODE_KATAKANA);
|
| - break;
|
| - case ui::TEXT_INPUT_MODE_KANA:
|
| - *new_conversion_mode |= (IME_CMODE_NATIVE
|
| - | IME_CMODE_FULLSHAPE);
|
| - *new_conversion_mode &= ~IME_CMODE_KATAKANA;
|
| - break;
|
| - case ui::TEXT_INPUT_MODE_KATAKANA:
|
| - *new_conversion_mode |= (IME_CMODE_NATIVE
|
| - | IME_CMODE_KATAKANA
|
| - | IME_CMODE_FULLSHAPE);
|
| - break;
|
| - default:
|
| - *open = FALSE;
|
| - break;
|
| - }
|
| -}
|
| -
|
| -} // namespace ui
|
|
|