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

Unified Diff: views/ime/input_method_win.cc

Issue 6688049: New InputMethod api for Views. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Update. Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « views/ime/input_method_win.h ('k') | views/ime/mock_input_method.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: views/ime/input_method_win.cc
diff --git a/views/ime/input_method_win.cc b/views/ime/input_method_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..007a0a65da69334832a7fe736bbeac7d5a215fd1
--- /dev/null
+++ b/views/ime/input_method_win.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "views/ime/input_method_win.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "ui/base/keycodes/keyboard_codes.h"
+#include "views/events/event.h"
+
+namespace views {
+
+InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate)
+ : delegate_(delegate),
+ widget_(NULL),
+ focused_view_(NULL),
+ widget_focused_(false),
+ active_(false),
+ direction_(base::i18n::UNKNOWN_DIRECTION),
+ pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION) {
+}
+
+InputMethodWin::~InputMethodWin() {
+ if (widget_) {
+ ime_input_.DisableIME(hwnd());
+ widget_->GetFocusManager()->RemoveFocusChangeListener(this);
+ widget_ = NULL;
+ }
+}
+
+void InputMethodWin::set_delegate(internal::InputMethodDelegate* delegate) {
+ delegate_ = delegate;
+}
+
+void InputMethodWin::Init(Widget* widget) {
+ DCHECK(widget);
+ DCHECK(widget->GetFocusManager());
+ DCHECK(widget->GetNativeView());
+
+ if (widget_ == widget) {
+ DLOG(ERROR) << "Already initialized.";
+ return;
+ }
+
+ DCHECK(!widget_);
+
+ widget_ = widget;
+ widget->GetFocusManager()->AddFocusChangeListener(this);
+
+ // Gets the initial input locale and text direction information.
+ OnInputLangChange(0, 0);
+}
+
+void InputMethodWin::DispatchKeyEvent(const KeyEvent& key) {
+ // Handles ctrl-shift key to change text direction and layout alignment.
+ if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() &&
+ GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
+ ui::KeyboardCode code = key.key_code();
+ if (key.type() == ui::ET_KEY_PRESSED) {
+ if (code == ui::VKEY_SHIFT) {
+ base::i18n::TextDirection dir;
+ if (ui::ImeInput::IsCtrlShiftPressed(&dir))
+ pending_requested_direction_ = dir;
+ } else if (code != ui::VKEY_CONTROL) {
+ pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
+ }
+ } else if (key.type() == ui::ET_KEY_RELEASED &&
+ (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) &&
+ pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) {
+ GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment(
+ pending_requested_direction_);
+ pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
+ }
+ }
+
+ DispatchKeyEventPostIME(key);
+}
+
+void InputMethodWin::OnTextInputTypeChanged(View* view) {
+ if (IsViewFocused(view)) {
+ ime_input_.CancelIME(hwnd());
+ UpdateIMEState();
+ }
+}
+
+void InputMethodWin::OnCaretBoundsChanged(View* view) {
+ if (!IsViewFocused(view))
+ return;
+
+ TextInputClient* client = view->GetTextInputClient();
+ if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return;
+
+ gfx::Rect rect = client->GetCaretBounds();
+ gfx::Point origin = rect.origin();
+ gfx::Point end = gfx::Point(rect.right(), rect.bottom());
+
+ View::ConvertPointToWidget(view, &origin);
+ View::ConvertPointToWidget(view, &end);
+
+ // We need to translate the coordinates to the toplevel widget if the view is
+ // inside a child widget.
+ if (view->GetWidget() != widget_) {
+ RECT win_rect;
+ win_rect.left = origin.x();
+ win_rect.top = origin.y();
+ win_rect.right = end.x();
+ win_rect.bottom = end.y();
+
+ ::MapWindowPoints(view->GetWidget()->GetNativeView(), hwnd(),
+ reinterpret_cast<LPPOINT>(&win_rect),
+ sizeof(RECT)/sizeof(POINT));
+ rect = win_rect;
oshima 2011/03/22 03:35:00 looks like this method is very similar to one in g
James Su 2011/03/22 08:39:35 Done.
+ } else {
+ rect = gfx::Rect(origin, gfx::Size(end.x() - origin.x(),
+ end.y() - origin.y()));
+ }
+
+ ime_input_.UpdateCaretRect(hwnd(), rect);
oshima 2011/03/22 03:35:00 and define template method to implement this for e
James Su 2011/03/22 08:39:35 Done.
+}
+
+void InputMethodWin::CancelComposition(View* view) {
+ if (IsViewFocused(view))
+ ime_input_.CancelIME(hwnd());
+}
+
+std::string InputMethodWin::GetInputLocale() {
+ return locale_;
+}
+
+base::i18n::TextDirection InputMethodWin::GetInputTextDirection() {
+ return direction_;
+}
+
+bool InputMethodWin::IsActive() {
+ return active_;
+}
+
+void InputMethodWin::FocusWillChange(View* focused_before, View* focused) {
+ DCHECK_EQ(focused_view_, focused_before);
+ ConfirmComposition();
+ focused_view_ = focused;
+ UpdateIMEState();
+}
+
+void InputMethodWin::OnSetFocus() {
+ if (!widget_focused_) {
+ widget_focused_ = true;
+ UpdateIMEState();
+ }
+}
+
+void InputMethodWin::OnKillFocus() {
+ if (widget_focused_) {
+ ConfirmComposition();
+ widget_focused_ = false;
+ }
+}
+
+void InputMethodWin::OnInputLangChange(DWORD character_set,
+ HKL input_language_id) {
+ active_ = ime_input_.SetInputLanguage();
+ locale_ = ime_input_.GetInputLanguageName();
+ direction_ = ime_input_.GetTextDirection();
+ OnInputMethodChanged();
+}
+
+LRESULT InputMethodWin::OnImeSetContext(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ active_ = (wparam == TRUE);
+ if (active_)
+ ime_input_.CreateImeWindow(hwnd());
+
+ OnInputMethodChanged();
+ return ime_input_.SetImeWindowStyle(hwnd(), message, wparam, lparam, handled);
+}
+
+LRESULT InputMethodWin::OnImeStartComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ // We have to prevent WTL from calling ::DefWindowProc() because the function
+ // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
+ // over-write the position of IME windows.
+ *handled = TRUE;
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return 0;
+
+ // Reset the composition status and create IME windows.
+ ime_input_.CreateImeWindow(hwnd());
+ ime_input_.ResetComposition(hwnd());
+ return 0;
+}
+
+LRESULT InputMethodWin::OnImeComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ // We have to prevent WTL from calling ::DefWindowProc() because we do not
+ // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
+ *handled = TRUE;
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return 0;
+
+ // At first, update the position of the IME window.
+ ime_input_.UpdateImeWindow(hwnd());
+
+ // Retrieve the result string and its attributes of the ongoing composition
+ // and send it to a renderer process.
+ ui::Composition composition;
+ if (ime_input_.GetResult(hwnd(), lparam, &composition.text)) {
+ GetTextInputClient()->InsertText(composition.text);
+ ime_input_.ResetComposition(hwnd());
+ // Fall though and try reading the composition string.
+ // Japanese IMEs send a message containing both GCS_RESULTSTR and
+ // GCS_COMPSTR, which means an ongoing composition has been finished
+ // by the start of another composition.
+ }
+ // Retrieve the composition string and its attributes of the ongoing
+ // composition and send it to a renderer process.
+ if (ime_input_.GetComposition(hwnd(), lparam, &composition))
+ GetTextInputClient()->SetComposition(composition);
+
+ return 0;
+}
+
+LRESULT InputMethodWin::OnImeEndComposition(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ // Let WTL call ::DefWindowProc() and release its resources.
+ *handled = FALSE;
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return 0;
+
+ if (GetTextInputClient()->HasComposition())
+ GetTextInputClient()->ClearComposition();
+
+ ime_input_.ResetComposition(hwnd());
+ ime_input_.DestroyImeWindow(hwnd());
+ return 0;
+}
+
+LRESULT InputMethodWin::OnChar(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ *handled = TRUE;
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return 0;
+
+ int flags = 0;
+ flags |= (::GetKeyState(VK_MENU) & 0x80)? ui::EF_ALT_DOWN : 0;
+ flags |= (::GetKeyState(VK_SHIFT) & 0x80)? ui::EF_SHIFT_DOWN : 0;
+ flags |= (::GetKeyState(VK_CONTROL) & 0x80)? ui::EF_CONTROL_DOWN : 0;
+ GetTextInputClient()->InsertChar(static_cast<char16>(wparam), flags);
+ return 0;
+}
+
+LRESULT InputMethodWin::OnDeadChar(
+ UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
+ *handled = TRUE;
+
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
+ return 0;
+
+ // Shows the dead character as a composition text, so that the user can know
+ // what dead key was pressed.
+ ui::Composition composition;
+ composition.text.assign(1, static_cast<char16>(wparam));
+ composition.selection = ui::Range(0, 1);
+ composition.underlines.push_back(
+ ui::CompositionUnderline(0, 1, SK_ColorBLACK, false));
+ GetTextInputClient()->SetComposition(composition);
+ return 0;
+}
+
+void InputMethodWin::ConfirmComposition() {
+ if (GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE) {
+ ime_input_.CleanupComposition(hwnd());
+ if (GetTextInputClient()->HasComposition())
+ GetTextInputClient()->ConfirmComposition();
+ }
+}
+
+void InputMethodWin::UpdateIMEState() {
+ if (GetTextInputType() == ui::TEXT_INPUT_TYPE_TEXT)
+ ime_input_.EnableIME(hwnd());
+ else
+ ime_input_.DisableIME(hwnd());
+}
+
+TextInputClient* InputMethodWin::GetTextInputClient() const {
+ return (widget_focused_ && focused_view_) ?
+ focused_view_->GetTextInputClient() : NULL;
+}
+
+ui::TextInputType InputMethodWin::GetTextInputType() const {
+ TextInputClient* client = GetTextInputClient();
+ return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
+}
+
+bool InputMethodWin::IsViewFocused(View* view) const {
+ return widget_focused_ && view && focused_view_ == view;
+}
+
+void InputMethodWin::DispatchKeyEventPostIME(const KeyEvent& key) const {
+ if (delegate_)
+ delegate_->DispatchKeyEventPostIME(key);
+}
+
+void InputMethodWin::OnInputMethodChanged() const {
+ TextInputClient* client = GetTextInputClient();
+ if (client && client->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE)
+ client->OnInputMethodChanged();
+}
+
+} // namespace views
« no previous file with comments | « views/ime/input_method_win.h ('k') | views/ime/mock_input_method.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698