input_method_win.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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; 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnChar(native_key_event.message, native_key_event.wParam, 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 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. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() && !IsTextInputTypeNone()) { 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO: shouldn't need to generate a KeyEvent here. 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::KeyEvent key(native_key_event, 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) native_key_event.message == WM_CHAR); 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::KeyboardCode code = key.key_code(); 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (key.type() == ui::ET_KEY_PRESSED) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (code == ui::VKEY_SHIFT) { 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::i18n::TextDirection dir; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ui::ImeInput::IsCtrlShiftPressed(&dir)) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_requested_direction_ = dir; 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (code != ui::VKEY_CONTROL) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (key.type() == ui::ET_KEY_RELEASED && 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) && 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) { 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment( 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_requested_direction_); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return DispatchKeyEventPostIME(native_key_event); 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputMethodWin::DispatchFabricatedKeyEvent(const ui::KeyEvent& event) { 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(ananta) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Support IMEs and RTL layout in Windows 8 metro Ash. The code below won't 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // work with IMEs. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Bug: https://code.google.com/p/chromium/issues/detail?id=164964 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (event.is_char()) { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (GetTextInputClient()) { 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetTextInputClient()->InsertChar(event.key_code(), 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ui::GetModifiersFromKeyState()); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return DispatchFabricatedKeyEventPostIME(event.type(), 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event.key_code(), 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event.flags()); 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodWin::OnInputLocaleChanged() { 927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) active_ = ime_input_.SetInputLanguage(); 937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) locale_ = ime_input_.GetInputLanguageName(); 947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) direction_ = ime_input_.GetTextDirection(); 957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) OnInputMethodChanged(); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string InputMethodWin::GetInputLocale() { 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return locale_; 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::i18n::TextDirection InputMethodWin::GetInputTextDirection() { 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return direction_; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputMethodWin::IsActive() { 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return active_; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnImeRequest(UINT message, 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WPARAM wparam, 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LPARAM lparam, 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BOOL* handled) { 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *handled = FALSE; 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Should not receive WM_IME_REQUEST message, if IME is disabled. 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const ui::TextInputType type = GetTextInputType(); 1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (type == ui::TEXT_INPUT_TYPE_NONE || 1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) type == ui::TEXT_INPUT_TYPE_PASSWORD) { 1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (wparam) { 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case IMR_RECONVERTSTRING: 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *handled = TRUE; 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam)); 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case IMR_DOCUMENTFEED: 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *handled = TRUE; 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam)); 130b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) case IMR_QUERYCHARPOSITION: 131b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *handled = TRUE; 132b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam)); 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)LRESULT InputMethodWin::OnChar(UINT message, 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) WPARAM wparam, 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LPARAM lparam, 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BOOL* handled) { 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *handled = TRUE; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // We need to send character events to the focused text input client event if 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // its text input type is ui::TEXT_INPUT_TYPE_NONE. 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (GetTextInputClient()) { 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) GetTextInputClient()->InsertChar(static_cast<char16>(wparam), 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ui::GetModifiersFromKeyState()); 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) HWND attached_window = GetAttachedWindowHandle(GetTextInputClient()); 1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (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. 1567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) if (message == WM_SYSCHAR && wparam == VK_SPACE && IsWindow(attached_window)) 1577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) ui::ShowSystemMenu(attached_window); 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