1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
27d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
37d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)// found in the LICENSE file.
47d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
57d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/base/ime/input_method_imm32.h"
67d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
77d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/basictypes.h"
87d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/base/ime/composition_text.h"
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "ui/base/ime/text_input_client.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "ui/base/ime/win/tsf_input_scope.h"
117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)namespace ui {
147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)InputMethodIMM32::InputMethodIMM32(internal::InputMethodDelegate* delegate,
167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                   HWND toplevel_window_handle)
177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    : InputMethodWin(delegate, toplevel_window_handle),
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      enabled_(false), is_candidate_popup_open_(false),
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      composing_window_handle_(NULL) {
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // In non-Aura environment, appropriate callbacks to OnFocus() and OnBlur()
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // are not implemented yet. To work around this limitation, here we use
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "always focused" model.
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(ime): Fix the caller of OnFocus() and OnBlur() so that appropriate
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // focus event will be passed.
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  InputMethodWin::OnFocus();
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnFocus() {
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Ignore OnFocus event for "always focused" model. See the comment in the
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // constructor.
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(ime): Implement OnFocus once the callers are fixed.
327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnBlur() {
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Ignore OnBlur event for "always focused" model. See the comment in the
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // constructor.
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(ime): Implement OnFocus once the callers are fixed.
387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool InputMethodIMM32::OnUntranslatedIMEMessage(
417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::NativeEvent& event, InputMethod::NativeEventResult* result) {
427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  LRESULT original_result = 0;
437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  BOOL handled = FALSE;
447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  switch (event.message) {
457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_IME_SETCONTEXT:
467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnImeSetContext(
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          event.hwnd, event.message, event.wParam, event.lParam, &handled);
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_IME_STARTCOMPOSITION:
507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnImeStartComposition(
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          event.hwnd, event.message, event.wParam, event.lParam, &handled);
527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_IME_COMPOSITION:
547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnImeComposition(
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          event.hwnd, event.message, event.wParam, event.lParam, &handled);
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_IME_ENDCOMPOSITION:
587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnImeEndComposition(
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          event.hwnd, event.message, event.wParam, event.lParam, &handled);
607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_IME_REQUEST:
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnImeRequest(
637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          event.message, event.wParam, event.lParam, &handled);
647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
657d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_CHAR:
667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_SYSCHAR:
677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnChar(
68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          event.hwnd, event.message, event.wParam, event.lParam, &handled);
697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_DEADCHAR:
717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case WM_SYSDEADCHAR:
727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      original_result = OnDeadChar(
737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          event.message, event.wParam, event.lParam, &handled);
747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case WM_IME_NOTIFY:
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      original_result = OnImeNotify(
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          event.message, event.wParam, event.lParam, &handled);
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    default:
807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      NOTREACHED() << "Unknown IME message:" << event.message;
817d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
827d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (result)
847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    *result = original_result;
857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return !!handled;
867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnTextInputTypeChanged(const TextInputClient* client) {
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (IsTextInputClientFocused(client) && IsWindowFocused(client)) {
909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    UpdateIMEState();
927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  InputMethodWin::OnTextInputTypeChanged(client);
947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnCaretBoundsChanged(const TextInputClient* client) {
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!enabled_ || !IsTextInputClientFocused(client) ||
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      !IsWindowFocused(client)) {
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return;
1001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // The current text input type should not be NONE if |client| is focused.
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DCHECK(!IsTextInputTypeNone());
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds());
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  HWND attached_window = GetAttachedWindowHandle(client);
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // conversion shouldn't be necessary.
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RECT r = {};
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  GetClientRect(attached_window, &r);
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  POINT window_point = { screen_bounds.x(), screen_bounds.y() };
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ScreenToClient(attached_window, &window_point);
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  gfx::Rect caret_rect(gfx::Point(window_point.x, window_point.y),
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                       screen_bounds.size());
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  imm32_manager_.UpdateCaretRect(attached_window, caret_rect);
1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::CancelComposition(const TextInputClient* client) {
1187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (enabled_ && IsTextInputClientFocused(client))
1199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    imm32_manager_.CancelIME(GetAttachedWindowHandle(client));
1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool InputMethodIMM32::IsCandidatePopupOpen() const {
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return is_candidate_popup_open_;
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnWillChangeFocusedClient(
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    TextInputClient* focused_before,
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    TextInputClient* focused) {
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (IsWindowFocused(focused_before)) {
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ConfirmCompositionText();
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::OnDidChangeFocusedClient(TextInputClient* focused_before,
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                TextInputClient* focused) {
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (IsWindowFocused(focused)) {
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Force to update the input type since client's TextInputStateChanged()
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // function might not be called if text input types before the client loses
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // focus and after it acquires focus again are the same.
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    OnTextInputTypeChanged(focused);
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    UpdateIMEState();
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Force to update caret bounds, in case the client thinks that the caret
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // bounds has not changed.
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    OnCaretBoundsChanged(focused);
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  InputMethodWin::OnDidChangeFocusedClient(focused_before, focused);
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT InputMethodIMM32::OnImeSetContext(HWND window_handle,
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                          UINT message,
1537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                          WPARAM wparam,
1547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                          LPARAM lparam,
1557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                          BOOL* handled) {
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!!wparam)
1579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    imm32_manager_.CreateImeWindow(window_handle);
1587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  OnInputMethodChanged();
1609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  return imm32_manager_.SetImeWindowStyle(
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      window_handle, message, wparam, lparam, handled);
1627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT InputMethodIMM32::OnImeStartComposition(HWND window_handle,
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                                UINT message,
1667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                WPARAM wparam,
1677d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                LPARAM lparam,
1687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                BOOL* handled) {
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // We have to prevent WTL from calling ::DefWindowProc() because the function
1707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
1717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // over-write the position of IME windows.
1727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  *handled = TRUE;
1737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Reset the composition status and create IME windows.
175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  composing_window_handle_ = window_handle;
1769ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  imm32_manager_.CreateImeWindow(window_handle);
1779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  imm32_manager_.ResetComposition(window_handle);
1787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return 0;
1797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
1807d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT InputMethodIMM32::OnImeComposition(HWND window_handle,
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                           UINT message,
1837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                           WPARAM wparam,
1847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                           LPARAM lparam,
1857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                           BOOL* handled) {
1867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // We have to prevent WTL from calling ::DefWindowProc() because we do not
1877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
1887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  *handled = TRUE;
1897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // At first, update the position of the IME window.
1919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  imm32_manager_.UpdateImeWindow(window_handle);
1927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Retrieve the result string and its attributes of the ongoing composition
1947d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // and send it to a renderer process.
1957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  ui::CompositionText composition;
1969ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (imm32_manager_.GetResult(window_handle, lparam, &composition.text)) {
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (!IsTextInputTypeNone())
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GetTextInputClient()->InsertText(composition.text);
1999ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    imm32_manager_.ResetComposition(window_handle);
2007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Fall though and try reading the composition string.
2017d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Japanese IMEs send a message containing both GCS_RESULTSTR and
2027d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // GCS_COMPSTR, which means an ongoing composition has been finished
2037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // by the start of another composition.
2047d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2057d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Retrieve the composition string and its attributes of the ongoing
2067d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // composition and send it to a renderer process.
2079ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  if (imm32_manager_.GetComposition(window_handle, lparam, &composition) &&
208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      !IsTextInputTypeNone())
2097d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    GetTextInputClient()->SetCompositionText(composition);
2107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return 0;
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT InputMethodIMM32::OnImeEndComposition(HWND window_handle,
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                              UINT message,
2167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                              WPARAM wparam,
2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                              LPARAM lparam,
2187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                              BOOL* handled) {
2197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Let WTL call ::DefWindowProc() and release its resources.
2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  *handled = FALSE;
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  composing_window_handle_ = NULL;
2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
224eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!IsTextInputTypeNone() && GetTextInputClient()->HasCompositionText())
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    GetTextInputClient()->ClearCompositionText();
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  imm32_manager_.ResetComposition(window_handle);
2289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  imm32_manager_.DestroyImeWindow(window_handle);
229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return 0;
230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochLRESULT InputMethodIMM32::OnImeNotify(UINT message,
233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      WPARAM wparam,
234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      LPARAM lparam,
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                      BOOL* handled) {
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  *handled = FALSE;
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool previous_state = is_candidate_popup_open_;
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Update |is_candidate_popup_open_|, whether a candidate window is open.
241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  switch (wparam) {
242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  case IMN_OPENCANDIDATE:
243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    is_candidate_popup_open_ = true;
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (!previous_state)
245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      OnCandidateWindowShown();
246eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    break;
247eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  case IMN_CLOSECANDIDATE:
248eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    is_candidate_popup_open_ = false;
249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (previous_state)
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      OnCandidateWindowHidden();
251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    break;
252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  case IMN_CHANGECANDIDATE:
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // TODO(kochi): The IME API expects this event to notify window size change,
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // while this may fire more often without window resize. There is no generic
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // way to get bounds of candidate window.
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    OnCandidateWindowUpdated();
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    break;
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
259eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return 0;
2617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2637d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::ConfirmCompositionText() {
264eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (composing_window_handle_)
2659ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    imm32_manager_.CleanupComposition(composing_window_handle_);
2667d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!IsTextInputTypeNone()) {
2687d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // Though above line should confirm the client's composition text by sending
2697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // a result text to us, in case the input method and the client are in
2707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    // inconsistent states, we check the client's composition state again.
2717d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (GetTextInputClient()->HasCompositionText())
2727d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      GetTextInputClient()->ConfirmCompositionText();
2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)void InputMethodIMM32::UpdateIMEState() {
2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Use switch here in case we are going to add more text input types.
2787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // We disable input method in password field.
27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const HWND window_handle = GetAttachedWindowHandle(GetTextInputClient());
28068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const TextInputType text_input_type = GetTextInputType();
28168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  const TextInputMode text_input_mode = GetTextInputMode();
28268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  switch (text_input_type) {
2837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case ui::TEXT_INPUT_TYPE_NONE:
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    case ui::TEXT_INPUT_TYPE_PASSWORD:
28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      imm32_manager_.DisableIME(window_handle);
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      enabled_ = false;
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    default:
28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      imm32_manager_.EnableIME(window_handle);
2907d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      enabled_ = true;
2917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      break;
2927d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
2937d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
29468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  imm32_manager_.SetTextInputMode(window_handle, text_input_mode);
29568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  tsf_inputscope::SetInputScopeForTsfUnawareWindow(
29668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      window_handle, text_input_type, text_input_mode);
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}  // namespace ui
300