12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/ime/input_method_win.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/events/event.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/events/event_constants.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/events/event_utils.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/ime/text_input_client.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/keycodes/keyboard_codes.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/base/win/hwnd_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace ui {
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace {
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Extra number of chars before and after selection (or composition) range which
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is returned to IME for improving conversion accuracy.
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const size_t kExtraNumberOfChars = 20;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                               HWND toplevel_window_handle)
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : active_(false),
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      toplevel_window_handle_(toplevel_window_handle),
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      direction_(base::i18n::UNKNOWN_DIRECTION),
297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SetDelegate(delegate);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputMethodWin::Init(bool focused) {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Gets the initial input locale and text direction information.
357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  OnInputLocaleChanged();
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InputMethodBase::Init(focused);
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputMethodWin::DispatchKeyEvent(
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::NativeEvent& native_key_event) {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (native_key_event.message == WM_CHAR) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BOOL handled;
44558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    OnChar(native_key_event.hwnd, native_key_event.message,
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch           native_key_event.wParam, native_key_event.lParam, &handled);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return !!handled;  // Don't send WM_CHAR for post event processing.
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Handles ctrl-shift key to change text direction and layout alignment.
499ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled() &&
509ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      !IsTextInputTypeNone()) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO: shouldn't need to generate a KeyEvent here.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ui::KeyEvent key(native_key_event,
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           native_key_event.message == WM_CHAR);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui::KeyboardCode code = key.key_code();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (key.type() == ui::ET_KEY_PRESSED) {
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (code == ui::VKEY_SHIFT) {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::i18n::TextDirection dir;
589ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        if (ui::IMM32Manager::IsCtrlShiftPressed(&dir))
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          pending_requested_direction_ = dir;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else if (code != ui::VKEY_CONTROL) {
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else if (key.type() == ui::ET_KEY_RELEASED &&
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) &&
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment(
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          pending_requested_direction_);
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return DispatchKeyEventPostIME(native_key_event);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputMethodWin::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) {
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(ananta)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Support IMEs and RTL layout in Windows 8 metro Ash. The code below won't
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // work with IMEs.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Bug: https://code.google.com/p/chromium/issues/detail?id=164964
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (event.is_char()) {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (GetTextInputClient()) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetTextInputClient()->InsertChar(event.key_code(),
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                       ui::GetModifiersFromKeyState());
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return DispatchFabricatedKeyEventPostIME(event.type(),
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           event.key_code(),
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           event.flags());
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodWin::OnInputLocaleChanged() {
939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  active_ = imm32_manager_.SetInputLanguage();
949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  locale_ = imm32_manager_.GetInputLanguageName();
959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  direction_ = imm32_manager_.GetTextDirection();
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  OnInputMethodChanged();
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string InputMethodWin::GetInputLocale() {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return locale_;
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::i18n::TextDirection InputMethodWin::GetInputTextDirection() {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return direction_;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputMethodWin::IsActive() {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return active_;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnImeRequest(UINT message,
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     WPARAM wparam,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     LPARAM lparam,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     BOOL* handled) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *handled = FALSE;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Should not receive WM_IME_REQUEST message, if IME is disabled.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ui::TextInputType type = GetTextInputType();
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (type == ui::TEXT_INPUT_TYPE_NONE ||
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      type == ui::TEXT_INPUT_TYPE_PASSWORD) {
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (wparam) {
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case IMR_RECONVERTSTRING:
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *handled = TRUE;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case IMR_DOCUMENTFEED:
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *handled = TRUE;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    case IMR_QUERYCHARPOSITION:
132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      *handled = TRUE;
133b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 0;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
139558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochLRESULT InputMethodWin::OnChar(HWND window_handle,
140558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                               UINT message,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               WPARAM wparam,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               LPARAM lparam,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               BOOL* handled) {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *handled = TRUE;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to send character events to the focused text input client event if
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // its text input type is ui::TEXT_INPUT_TYPE_NONE.
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (GetTextInputClient()) {
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    GetTextInputClient()->InsertChar(static_cast<char16>(wparam),
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     ui::GetModifiersFromKeyState());
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Explicitly show the system menu at a good location on [Alt]+[Space].
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  //       menu causes undesirable titlebar artifacts in the classic theme.
156558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (message == WM_SYSCHAR && wparam == VK_SPACE)
157558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    ui::ShowSystemMenu(window_handle);
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return 0;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnDeadChar(UINT message,
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   WPARAM wparam,
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   LPARAM lparam,
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   BOOL* handled) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *handled = TRUE;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (IsTextInputTypeNone())
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetTextInputClient())
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Shows the dead character as a composition text, so that the user can know
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // what dead key was pressed.
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::CompositionText composition;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  composition.text.assign(1, static_cast<char16>(wparam));
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  composition.selection = ui::Range(0, 1);
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  composition.underlines.push_back(
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui::CompositionUnderline(0, 1, SK_ColorBLACK, false));
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetTextInputClient()->SetCompositionText(composition);
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return 0;
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::TextInputClient* client = GetTextInputClient();
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client)
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::Range text_range;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client->GetTextRange(&text_range) || text_range.is_empty())
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool result = false;
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::Range target_range;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (client->HasCompositionText())
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result = client->GetCompositionTextRange(&target_range);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!result || target_range.is_empty()) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!client->GetSelectionRange(&target_range) ||
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        !target_range.IsValid()) {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return 0;
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!text_range.Contains(target_range))
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    text_range.set_start(target_range.GetMin() - kExtraNumberOfChars);
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    text_range.set_end(target_range.GetMax() + kExtraNumberOfChars);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t len = text_range.length();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!reconv)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return need_size;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (reconv->dwSize < need_size)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string16 text;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetTextInputClient()->GetTextFromRange(text_range, &text))
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(text_range.length(), text.length());
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwVersion = 0;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwStrLen = len;
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwCompStrLen =
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client->HasCompositionText() ? target_range.length() : 0;
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwCompStrOffset =
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (target_range.GetMin() - text_range.start()) * sizeof(WCHAR);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwTargetStrLen = target_range.length();
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy((char*)reconv + sizeof(RECONVERTSTRING),
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         text.c_str(), len * sizeof(WCHAR));
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
24290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // According to Microsoft API document, IMR_RECONVERTSTRING and
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // IMR_DOCUMENTFEED should return reconv, but some applications return
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // need_size.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return reinterpret_cast<LRESULT>(reconv);
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) {
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::TextInputClient* client = GetTextInputClient();
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If there is a composition string already, we don't allow reconversion.
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (client->HasCompositionText())
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::Range text_range;
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client->GetTextRange(&text_range) || text_range.is_empty())
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui::Range selection_range;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!client->GetSelectionRange(&selection_range) ||
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      selection_range.is_empty()) {
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(text_range.Contains(selection_range));
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t len = selection_range.length();
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!reconv)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return need_size;
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (reconv->dwSize < need_size)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(penghuang): Return some extra context to help improve IME's
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // reconversion accuracy.
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string16 text;
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetTextInputClient()->GetTextFromRange(selection_range, &text))
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return 0;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(selection_range.length(), text.length());
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwVersion = 0;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwStrLen = len;
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwCompStrLen = len;
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwCompStrOffset = 0;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwTargetStrLen = len;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  reconv->dwTargetStrOffset = 0;
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         text.c_str(), len * sizeof(WCHAR));
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
29690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // According to Microsoft API document, IMR_RECONVERTSTRING and
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // IMR_DOCUMENTFEED should return reconv, but some applications return
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // need_size.
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return reinterpret_cast<LRESULT>(reconv);
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)LRESULT InputMethodWin::OnQueryCharPosition(IMECHARPOSITION* char_positon) {
303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!char_positon)
304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 0;
305b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
306b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (char_positon->dwSize < sizeof(IMECHARPOSITION))
307b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 0;
308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  ui::TextInputClient* client = GetTextInputClient();
310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!client)
311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return 0;
312b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
313b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  gfx::Rect rect;
31490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (client->HasCompositionText()) {
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!client->GetCompositionCharacterBounds(char_positon->dwCharPos,
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                               &rect)) {
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return 0;
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  } else {
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // If there is no composition and the first character is queried, returns
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the caret bounds. This behavior is the same to that of RichEdit control.
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (char_positon->dwCharPos != 0)
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return 0;
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    rect = client->GetCaretBounds();
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
326b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
327b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  char_positon->pt.x = rect.x();
328b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  char_positon->pt.y = rect.y();
329b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  char_positon->cLineHeight = rect.height();
330b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return 1;  // returns non-zero value when succeeded.
331b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
332b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)HWND InputMethodWin::GetAttachedWindowHandle(
3347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const TextInputClient* text_input_client) const {
3357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // On Aura environment, we can assume that |toplevel_window_handle_| always
3367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // represents the valid top-level window handle because each top-level window
3377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // is responsible for lifecycle management of corresponding InputMethod
3387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // instance.
3397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#if defined(USE_AURA)
3407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return toplevel_window_handle_;
3417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#else
3427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // On Non-Aura environment, TextInputClient::GetAttachedWindow() returns
3437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // window handle to which each input method is bound.
3447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!text_input_client)
3457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return NULL;
3467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return text_input_client->GetAttachedWindow();
3477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#endif
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace ui
351