diff options
26 files changed, 740 insertions, 162 deletions
diff --git a/ash/shell.cc b/ash/shell.cc index ffdcf99..5d8b830 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -474,7 +474,8 @@ void Shell::Init() { AddPreTargetHandler(overlay_filter_.get()); AddShellObserver(overlay_filter_.get()); - input_method_filter_.reset(new views::corewm::InputMethodEventFilter); + input_method_filter_.reset(new views::corewm::InputMethodEventFilter( + root_window->GetAcceleratedWidget())); AddPreTargetHandler(input_method_filter_.get()); #if !defined(OS_MACOSX) diff --git a/content/shell/shell_stacking_client_ash.cc b/content/shell/shell_stacking_client_ash.cc index a0b4f8d..f9e7c0a 100644 --- a/content/shell/shell_stacking_client_ash.cc +++ b/content/shell/shell_stacking_client_ash.cc @@ -38,7 +38,8 @@ aura::Window* ShellStackingClientAsh::GetDefaultParent( // Pass ownership of the filter to the root_window. root_window_->SetEventFilter(root_window_event_filter_); - input_method_filter_.reset(new views::corewm::InputMethodEventFilter); + input_method_filter_.reset(new views::corewm::InputMethodEventFilter( + root_window_->GetAcceleratedWidget())); input_method_filter_->SetInputMethodPropertyInRootWindow( root_window_.get()); root_window_event_filter_->AddHandler(input_method_filter_.get()); diff --git a/ui/base/ime/ime.gypi b/ui/base/ime/ime.gypi index f5eb297..2c71632 100644 --- a/ui/base/ime/ime.gypi +++ b/ui/base/ime/ime.gypi @@ -20,6 +20,8 @@ 'input_method_factory.h', 'input_method_ibus.cc', 'input_method_ibus.h', + 'input_method_win.cc', + 'input_method_win.h', 'mock_input_method.cc', 'mock_input_method.h', 'text_input_client.cc', diff --git a/ui/base/ime/input_method.h b/ui/base/ime/input_method.h index c7d93cc..ae63be1 100644 --- a/ui/base/ime/input_method.h +++ b/ui/base/ime/input_method.h @@ -80,6 +80,7 @@ class InputMethod { virtual void DispatchKeyEvent(const base::NativeEvent& native_key_event) = 0; // TODO(yusukes): Add DispatchFabricatedKeyEvent to support virtual keyboards. + // TODO(yusukes): both win and ibus override to do nothing. Is this needed? virtual void DispatchFabricatedKeyEvent(const ui::KeyEvent& event) = 0; // Called by the focused client whenever its text input type is changed. diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc index b6fa482..c1b094b 100644 --- a/ui/base/ime/input_method_base.cc +++ b/ui/base/ime/input_method_base.cc @@ -19,8 +19,7 @@ InputMethodBase::InputMethodBase() InputMethodBase::~InputMethodBase() { } -void InputMethodBase::SetDelegate( - internal::InputMethodDelegate* delegate) { +void InputMethodBase::SetDelegate(internal::InputMethodDelegate* delegate) { delegate_ = delegate; } diff --git a/ui/base/ime/input_method_factory.cc b/ui/base/ime/input_method_factory.cc index 33f7698..5bb5be0 100644 --- a/ui/base/ime/input_method_factory.cc +++ b/ui/base/ime/input_method_factory.cc @@ -8,15 +8,20 @@ #if defined(OS_CHROMEOS) #include "ui/base/ime/input_method_ibus.h" +#elif defined(OS_WIN) +#include "ui/base/ime/input_method_win.h" #else #include "ui/base/ime/mock_input_method.h" #endif namespace ui { -InputMethod* CreateInputMethod(internal::InputMethodDelegate* delegate) { +InputMethod* CreateInputMethod(internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget) { #if defined(OS_CHROMEOS) return new InputMethodIBus(delegate); +#elif defined(OS_WIN) + return new InputMethodWin(delegate, widget); #else return new MockInputMethod(delegate); #endif diff --git a/ui/base/ime/input_method_factory.h b/ui/base/ime/input_method_factory.h index 9bb81bc..db56bf74 100644 --- a/ui/base/ime/input_method_factory.h +++ b/ui/base/ime/input_method_factory.h @@ -6,6 +6,7 @@ #define UI_BASE_IME_INPUT_METHOD_FACTORY_H_ #include "ui/base/ui_export.h" +#include "ui/gfx/native_widget_types.h" namespace ui { @@ -18,7 +19,8 @@ class InputMethodDelegate; // Creates and returns an input method implementation for the platform. Caller // must delete the object. The object does not own |delegate|. UI_EXPORT InputMethod* CreateInputMethod( - internal::InputMethodDelegate* delegate); + internal::InputMethodDelegate* delegate, + gfx::AcceleratedWidget widget); } // namespace ui; diff --git a/ui/base/ime/input_method_win.cc b/ui/base/ime/input_method_win.cc new file mode 100644 index 0000000..3e6474e --- /dev/null +++ b/ui/base/ime/input_method_win.cc @@ -0,0 +1,486 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/ime/input_method_win.h" + +#include "base/basictypes.h" +#include "base/debug/stack_trace.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "ui/base/events/event.h" +#include "ui/base/events/event_constants.h" +#include "ui/base/events/event_utils.h" +#include "ui/base/ime/composition_text.h" +#include "ui/base/ime/input_method.h" +#include "ui/base/ime/text_input_client.h" +#include "ui/base/keycodes/keyboard_codes.h" + +// Extra number of chars before and after selection (or composition) range which +// is returned to IME for improving conversion accuracy. +static const size_t kExtraNumberOfChars = 20; + +namespace ui { + +InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate, + HWND hwnd) + : hwnd_(hwnd), + active_(false), + direction_(base::i18n::UNKNOWN_DIRECTION), + pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION), + enabled_(false) { + SetDelegate(delegate); +} + +InputMethodWin::~InputMethodWin() { + ime_input_.DisableIME(hwnd_); +} + +void InputMethodWin::Init(bool focused) { + // Gets the initial input locale and text direction information. + OnInputLangChange(0, 0); + + InputMethodBase::Init(focused); +} + +void InputMethodWin::OnFocus() { + InputMethodBase::OnFocus(); + UpdateIMEState(); +} + +void InputMethodWin::OnBlur() { + ConfirmCompositionText(); + InputMethodBase::OnBlur(); +} + +void InputMethodWin::DispatchKeyEvent( + const base::NativeEvent& native_key_event) { + if (native_key_event.message == WM_CHAR) { + BOOL handled; + OnChar(native_key_event.message, native_key_event.wParam, + native_key_event.lParam, &handled); + return; // Don't send WM_CHAR for post event processing. + } + // Handles ctrl-shift key to change text direction and layout alignment. + if (ui::ImeInput::IsRTLKeyboardLayoutInstalled() && !IsTextInputTypeNone()) { + // TODO: shouldn't need to generate a KeyEvent here. + const ui::KeyEvent key(native_key_event, + native_key_event.message == WM_CHAR); + 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(native_key_event); +} + +void InputMethodWin::OnTextInputTypeChanged(const TextInputClient* client) { + if (IsTextInputClientFocused(client)) { + ime_input_.CancelIME(hwnd_); + UpdateIMEState(); + } + InputMethodBase::OnTextInputTypeChanged(client); +} + +void InputMethodWin::OnCaretBoundsChanged(const TextInputClient* client) { + if (!enabled_ || !IsTextInputClientFocused(client)) + return; + + // The current text input type should not be NONE if |client| is focused. + DCHECK(!IsTextInputTypeNone()); + gfx::Rect screen_bounds(GetTextInputClient()->GetCaretBounds()); + // TODO(ime): see comment in TextInputClient::GetCaretBounds(), this + // conversion shouldn't be necessary. + RECT r; + GetClientRect(hwnd_, &r); + POINT window_point = { screen_bounds.x(), screen_bounds.y() }; + ScreenToClient(hwnd_, &window_point); + ime_input_.UpdateCaretRect( + hwnd_, + gfx::Rect(gfx::Point(window_point.x, window_point.y), + screen_bounds.size())); +} + +void InputMethodWin::CancelComposition(const TextInputClient* client) { + if (enabled_ && IsTextInputClientFocused(client)) + ime_input_.CancelIME(hwnd_); +} + +std::string InputMethodWin::GetInputLocale() { + return locale_; +} + +base::i18n::TextDirection InputMethodWin::GetInputTextDirection() { + return direction_; +} + +bool InputMethodWin::IsActive() { + return active_; +} + +LRESULT InputMethodWin::OnImeMessages(UINT message, + WPARAM w_param, + LPARAM l_param, + BOOL* handled) { + LRESULT result = 0; + switch (message) { + case WM_IME_SETCONTEXT: + result = OnImeSetContext(message, w_param, l_param, handled); + break; + case WM_IME_STARTCOMPOSITION: + result = OnImeStartComposition(message, w_param, l_param, handled); + break; + case WM_IME_COMPOSITION: + result = OnImeComposition(message, w_param, l_param, handled); + break; + case WM_IME_ENDCOMPOSITION: + result = OnImeEndComposition(message, w_param, l_param, handled); + break; + case WM_IME_REQUEST: + result = OnImeRequest(message, w_param, l_param, handled); + break; + case WM_CHAR: + case WM_SYSCHAR: + result = OnChar(message, w_param, l_param, handled); + break; + case WM_DEADCHAR: + case WM_SYSDEADCHAR: + result = OnDeadChar(message, w_param, l_param, handled); + break; + default: + NOTREACHED() << "Unknown IME message:" << message; + break; + } + return result; +} + +void InputMethodWin::OnInputLangChange(DWORD character_set, + HKL input_language_id) { + active_ = ime_input_.SetInputLanguage(); + locale_ = ime_input_.GetInputLanguageName(); + direction_ = ime_input_.GetTextDirection(); + OnInputMethodChanged(); +} + +void InputMethodWin::OnWillChangeFocusedClient(TextInputClient* focused_before, + TextInputClient* focused) { + ConfirmCompositionText(); +} + +void InputMethodWin::OnDidChangeFocusedClient(TextInputClient* focused_before, + TextInputClient* focused) { + // Force to update the input type since client's TextInputStateChanged() + // function might not be called if text input types before the client loses + // focus and after it acquires focus again are the same. + OnTextInputTypeChanged(focused); + + UpdateIMEState(); + + // Force to update caret bounds, in case the client thinks that the caret + // bounds has not changed. + OnCaretBoundsChanged(focused); +} + +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 (IsTextInputTypeNone()) + 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 (IsTextInputTypeNone()) + 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::CompositionText 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()->SetCompositionText(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 (IsTextInputTypeNone()) + return 0; + + if (GetTextInputClient()->HasCompositionText()) + GetTextInputClient()->ClearCompositionText(); + + ime_input_.ResetComposition(hwnd_); + ime_input_.DestroyImeWindow(hwnd_); + return 0; +} + +LRESULT InputMethodWin::OnImeRequest(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled) { + *handled = FALSE; + + // Should not receive WM_IME_REQUEST message, if IME is disabled. + const ui::TextInputType type = GetTextInputType(); + if (type == ui::TEXT_INPUT_TYPE_NONE || + type == ui::TEXT_INPUT_TYPE_PASSWORD) { + return 0; + } + + switch (wparam) { + case IMR_RECONVERTSTRING: + *handled = TRUE; + return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam)); + case IMR_DOCUMENTFEED: + *handled = TRUE; + return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam)); + default: + return 0; + } +} + +LRESULT InputMethodWin::OnChar(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled) { + *handled = TRUE; + + // We need to send character events to the focused text input client event if + // its text input type is ui::TEXT_INPUT_TYPE_NONE. + if (!GetTextInputClient()) + return 0; + + GetTextInputClient()->InsertChar(static_cast<char16>(wparam), + ui::GetModifiersFromKeyState()); + return 0; +} + +LRESULT InputMethodWin::OnDeadChar(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled) { + *handled = TRUE; + + if (IsTextInputTypeNone()) + return 0; + + if (!GetTextInputClient()) + return 0; + + // Shows the dead character as a composition text, so that the user can know + // what dead key was pressed. + ui::CompositionText 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()->SetCompositionText(composition); + return 0; +} + +LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) { + ui::TextInputClient* client = GetTextInputClient(); + if (!client) + return 0; + + ui::Range text_range; + if (!client->GetTextRange(&text_range) || text_range.is_empty()) + return 0; + + bool result = false; + ui::Range target_range; + if (client->HasCompositionText()) + result = client->GetCompositionTextRange(&target_range); + + if (!result || target_range.is_empty()) { + if (!client->GetSelectionRange(&target_range) || + !target_range.IsValid()) { + return 0; + } + } + + if (!text_range.Contains(target_range)) + return 0; + + if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars) + text_range.set_start(target_range.GetMin() - kExtraNumberOfChars); + + if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars) + text_range.set_end(target_range.GetMax() + kExtraNumberOfChars); + + size_t len = text_range.length(); + size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); + + if (!reconv) + return need_size; + + if (reconv->dwSize < need_size) + return 0; + + string16 text; + if (!GetTextInputClient()->GetTextFromRange(text_range, &text)) + return 0; + DCHECK_EQ(text_range.length(), text.length()); + + reconv->dwVersion = 0; + reconv->dwStrLen = len; + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = + client->HasCompositionText() ? target_range.length() : 0; + reconv->dwCompStrOffset = + (target_range.GetMin() - text_range.start()) * sizeof(WCHAR); + reconv->dwTargetStrLen = target_range.length(); + reconv->dwTargetStrOffset = reconv->dwCompStrOffset; + + memcpy((char*)reconv + sizeof(RECONVERTSTRING), + text.c_str(), len * sizeof(WCHAR)); + + // According to Microsft API document, IMR_RECONVERTSTRING and + // IMR_DOCUMENTFEED should return reconv, but some applications return + // need_size. + return reinterpret_cast<LRESULT>(reconv); +} + +LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) { + ui::TextInputClient* client = GetTextInputClient(); + if (!client) + return 0; + + // If there is a composition string already, we don't allow reconversion. + if (client->HasCompositionText()) + return 0; + + ui::Range text_range; + if (!client->GetTextRange(&text_range) || text_range.is_empty()) + return 0; + + ui::Range selection_range; + if (!client->GetSelectionRange(&selection_range) || + selection_range.is_empty()) { + return 0; + } + + DCHECK(text_range.Contains(selection_range)); + + size_t len = selection_range.length(); + size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR); + + if (!reconv) + return need_size; + + if (reconv->dwSize < need_size) + return 0; + + // TODO(penghuang): Return some extra context to help improve IME's + // reconversion accuracy. + string16 text; + if (!GetTextInputClient()->GetTextFromRange(selection_range, &text)) + return 0; + DCHECK_EQ(selection_range.length(), text.length()); + + reconv->dwVersion = 0; + reconv->dwStrLen = len; + reconv->dwStrOffset = sizeof(RECONVERTSTRING); + reconv->dwCompStrLen = len; + reconv->dwCompStrOffset = 0; + reconv->dwTargetStrLen = len; + reconv->dwTargetStrOffset = 0; + + memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING), + text.c_str(), len * sizeof(WCHAR)); + + // According to Microsft API document, IMR_RECONVERTSTRING and + // IMR_DOCUMENTFEED should return reconv, but some applications return + // need_size. + return reinterpret_cast<LRESULT>(reconv); +} + +void InputMethodWin::ConfirmCompositionText() { + if (!IsTextInputTypeNone()) { + ime_input_.CleanupComposition(hwnd_); + // Though above line should confirm the client's composition text by sending + // a result text to us, in case the input method and the client are in + // inconsistent states, we check the client's composition state again. + if (GetTextInputClient()->HasCompositionText()) + GetTextInputClient()->ConfirmCompositionText(); + } +} + +void InputMethodWin::UpdateIMEState() { + // Use switch here in case we are going to add more text input types. + // We disable input method in password field. + switch (GetTextInputType()) { + case ui::TEXT_INPUT_TYPE_NONE: + case ui::TEXT_INPUT_TYPE_PASSWORD: + ime_input_.DisableIME(hwnd_); + enabled_ = false; + break; + default: + ime_input_.EnableIME(hwnd_); + enabled_ = true; + break; + } +} + +} // namespace ui diff --git a/ui/base/ime/input_method_win.h b/ui/base/ime/input_method_win.h new file mode 100644 index 0000000..414b490 --- /dev/null +++ b/ui/base/ime/input_method_win.h @@ -0,0 +1,119 @@ +// 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. + +#ifndef UI_BASE_IME_INPUT_METHOD_WIN_H_ +#define UI_BASE_IME_INPUT_METHOD_WIN_H_ + +#include <windows.h> + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ui/base/ime/input_method_base.h" +#include "ui/base/win/ime_input.h" + +namespace ui { + +// An InputMethod implementation based on Windows IMM32 API. +class UI_EXPORT InputMethodWin : public InputMethodBase { + public: + explicit InputMethodWin(internal::InputMethodDelegate* delegate, HWND hwnd); + virtual ~InputMethodWin(); + + // Overridden from InputMethod: + virtual void Init(bool focused) OVERRIDE; + virtual void OnFocus() OVERRIDE; + virtual void OnBlur() OVERRIDE; + virtual void DispatchKeyEvent( + const base::NativeEvent& native_key_event) OVERRIDE; + virtual void DispatchFabricatedKeyEvent(const ui::KeyEvent& event) OVERRIDE {} + virtual void OnTextInputTypeChanged(const TextInputClient* client) OVERRIDE; + virtual void OnCaretBoundsChanged(const TextInputClient* client) OVERRIDE; + virtual void CancelComposition(const TextInputClient* client) OVERRIDE; + virtual std::string GetInputLocale() OVERRIDE; + virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE; + virtual bool IsActive() OVERRIDE; + + // Handles IME messages. + LRESULT OnImeMessages(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + + // Message handlers. The native widget is responsible for forwarding following + // messages to the input method. + void OnInputLangChange(DWORD character_set, HKL input_language_id); + + protected: + // Overridden from InputMethodBase: + virtual void OnWillChangeFocusedClient(TextInputClient* focused_before, + TextInputClient* focused) OVERRIDE; + virtual void OnDidChangeFocusedClient(TextInputClient* focused_before, + TextInputClient* focused) OVERRIDE; + + private: + LRESULT OnImeSetContext(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + LRESULT OnImeStartComposition(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + LRESULT OnImeComposition(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + LRESULT OnImeEndComposition(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + LRESULT OnImeRequest(UINT message, + WPARAM wparam, + LPARAM lparam, + BOOL* handled); + // For both WM_CHAR and WM_SYSCHAR + LRESULT OnChar(UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled); + // For both WM_DEADCHAR and WM_SYSDEADCHAR + LRESULT OnDeadChar(UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled); + + LRESULT OnDocumentFeed(RECONVERTSTRING *reconv); + LRESULT OnReconvertString(RECONVERTSTRING *reconv); + + // Asks the client to confirm current composition text. + void ConfirmCompositionText(); + + // Enables or disables the IME according to the current text input type. + void UpdateIMEState(); + + // The HWND this InputMethod is bound to. + HWND hwnd_; + + // Indicates if the current input locale has an IME. + bool active_; + + // Name of the current input locale. + std::string locale_; + + // The current input text direction. + base::i18n::TextDirection direction_; + + // The new text direction and layout alignment requested by the user by + // pressing ctrl-shift. It'll be sent to the text input client when the key + // is released. + base::i18n::TextDirection pending_requested_direction_; + + // Windows IMM32 wrapper. + // (See "ui/base/win/ime_input.h" for its details.) + ui::ImeInput ime_input_; + + bool enabled_; + + DISALLOW_COPY_AND_ASSIGN(InputMethodWin); +}; + +} // namespace ui + +#endif // UI_BASE_IME_INPUT_METHOD_WIN_H_ diff --git a/ui/views/corewm/input_method_event_filter.cc b/ui/views/corewm/input_method_event_filter.cc index 350ab4f..f80d3ca 100644 --- a/ui/views/corewm/input_method_event_filter.cc +++ b/ui/views/corewm/input_method_event_filter.cc @@ -16,9 +16,9 @@ namespace corewm { //////////////////////////////////////////////////////////////////////////////// // InputMethodEventFilter, public: -InputMethodEventFilter::InputMethodEventFilter() +InputMethodEventFilter::InputMethodEventFilter(gfx::AcceleratedWidget widget) : ALLOW_THIS_IN_INITIALIZER_LIST( - input_method_(ui::CreateInputMethod(this))), + input_method_(ui::CreateInputMethod(this, widget))), target_root_window_(NULL) { // TODO(yusukes): Check if the root window is currently focused and pass the // result to Init(). diff --git a/ui/views/corewm/input_method_event_filter.h b/ui/views/corewm/input_method_event_filter.h index 99a42c3..c0d3a94 100644 --- a/ui/views/corewm/input_method_event_filter.h +++ b/ui/views/corewm/input_method_event_filter.h @@ -10,6 +10,7 @@ #include "base/memory/scoped_ptr.h" #include "ui/base/events/event_handler.h" #include "ui/base/ime/input_method_delegate.h" +#include "ui/gfx/native_widget_types.h" #include "ui/views/views_export.h" namespace aura { @@ -29,7 +30,7 @@ class VIEWS_EXPORT InputMethodEventFilter : public ui::EventHandler, public ui::internal::InputMethodDelegate { public: - InputMethodEventFilter(); + explicit InputMethodEventFilter(gfx::AcceleratedWidget widget); virtual ~InputMethodEventFilter(); void SetInputMethodPropertyInRootWindow(aura::RootWindow* root_window); diff --git a/ui/views/corewm/input_method_event_filter_unittest.cc b/ui/views/corewm/input_method_event_filter_unittest.cc index c4e7b5a..a5927ab 100644 --- a/ui/views/corewm/input_method_event_filter_unittest.cc +++ b/ui/views/corewm/input_method_event_filter_unittest.cc @@ -32,7 +32,8 @@ TEST_F(InputMethodEventFilterTest, TestInputMethodProperty) { CompoundEventFilter* root_filter = new CompoundEventFilter; root_window()->SetEventFilter(root_filter); - InputMethodEventFilter input_method_event_filter; + InputMethodEventFilter input_method_event_filter( + root_window()->GetAcceleratedWidget()); root_filter->AddHandler(&input_method_event_filter); // Tests if InputMethodEventFilter adds a window property on its @@ -50,7 +51,8 @@ TEST_F(InputMethodEventFilterTest, TestInputMethodKeyEventPropagation) { root_window()->SetEventFilter(root_filter); // Add the InputMethodEventFilter before the TestEventFilter. - InputMethodEventFilter input_method_event_filter; + InputMethodEventFilter input_method_event_filter( + root_window()->GetAcceleratedWidget()); root_filter->AddHandler(&input_method_event_filter); // Add TestEventFilter to the RootWindow. diff --git a/ui/views/ime/input_method_bridge.cc b/ui/views/ime/input_method_bridge.cc index 438e3308..58b5f84 100644 --- a/ui/views/ime/input_method_bridge.cc +++ b/ui/views/ime/input_method_bridge.cc @@ -43,7 +43,9 @@ void InputMethodBridge::OnFocus() { } void InputMethodBridge::OnBlur() { - DCHECK(widget_focused()); + // win32 sends multiple focus lost events, ignore all but the first. + if (widget_focused()) + return; ConfirmCompositionText(); InputMethodBase::OnBlur(); diff --git a/ui/views/ime/input_method_delegate.h b/ui/views/ime/input_method_delegate.h index f2a2479..59bc9dc 100644 --- a/ui/views/ime/input_method_delegate.h +++ b/ui/views/ime/input_method_delegate.h @@ -23,7 +23,6 @@ class VIEWS_EXPORT InputMethodDelegate { // Dispatch a key event already processed by the input method. virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) = 0; - }; } // namespace internal diff --git a/ui/views/ime/input_method_win.cc b/ui/views/ime/input_method_win.cc index f29bceb..d7b15cf 100644 --- a/ui/views/ime/input_method_win.cc +++ b/ui/views/ime/input_method_win.cc @@ -45,24 +45,13 @@ void InputMethodWin::Init(Widget* widget) { } void InputMethodWin::OnFocus() { -#if !defined(USE_AURA) - // On Aura, there are different ways of getting here (HWNDMessageHandler and - // FocusManager) and since they don't know about the focus state that each - // other is in, this DCHECK comes up. - // TODO(ime): ifdefing this out is a hack, the root problem needs to be - // addressed. DCHECK(!widget_focused()); -#endif InputMethodBase::OnFocus(); UpdateIMEState(); } void InputMethodWin::OnBlur() { -#if !defined(USE_AURA) - // TODO(ime): ifdefing this out is a hack, the root problem needs to be - // addressed. DCHECK(widget_focused()); -#endif ConfirmCompositionText(); InputMethodBase::OnBlur(); } diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 2d82e32..edc77d6 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -473,8 +473,6 @@ }], ['OS=="win"', { 'sources/': [ - ['include', 'ime/input_method_win.cc'], - ['include', 'ime/input_method_win.h'], ['include', 'widget/desktop_aura/desktop_screen_win.cc'], ['include', 'widget/desktop_aura/desktop_screen_win.h'], ['include', 'widget/desktop_aura/desktop_root_window_host_win.cc'], diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index b03b41e..0a11531 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc @@ -15,7 +15,10 @@ #include "ui/compositor/layer.h" #include "ui/gfx/canvas.h" #include "ui/native_theme/native_theme.h" +#include "ui/views/corewm/compound_event_filter.h" +#include "ui/views/corewm/input_method_event_filter.h" #include "ui/views/ime/input_method.h" +#include "ui/views/ime/input_method_bridge.h" #include "ui/views/widget/desktop_aura/desktop_root_window_host.h" #include "ui/views/widget/native_widget_aura_window_observer.h" #include "ui/views/widget/widget.h" @@ -85,11 +88,30 @@ DesktopNativeWidgetAura* DesktopNativeWidgetAura::ForWindow( } void DesktopNativeWidgetAura::OnHostClosed() { + root_window_event_filter_->RemoveHandler(input_method_event_filter_.get()); // This will, through a long list of callbacks, trigger |root_window_| going // away. See OnWindowDestroyed() delete window_; } +void DesktopNativeWidgetAura::InstallInputMethodEventFilter( + aura::RootWindow* root) { + DCHECK(!input_method_event_filter_.get()); + + // CEF sets focus to the window the user clicks down on. + // TODO(beng): see if we can't do this some other way. CEF seems a heavy- + // handed way of accomplishing focus. + // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow. + root_window_event_filter_ = new corewm::CompoundEventFilter; + // Pass ownership of the filter to the root_window. + root->SetEventFilter(root_window_event_filter_); + + input_method_event_filter_.reset( + new corewm::InputMethodEventFilter(root->GetAcceleratedWidget())); + input_method_event_filter_->SetInputMethodPropertyInRootWindow(root); + root_window_event_filter_->AddHandler(input_method_event_filter_.get()); +} + //////////////////////////////////////////////////////////////////////////////// // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation: @@ -208,12 +230,13 @@ bool DesktopNativeWidgetAura::HasCapture() const { } InputMethod* DesktopNativeWidgetAura::CreateInputMethod() { - return desktop_root_window_host_->CreateInputMethod(); + ui::InputMethod* host = input_method_event_filter_->input_method(); + return new InputMethodBridge(this, host); } internal::InputMethodDelegate* DesktopNativeWidgetAura::GetInputMethodDelegate() { - return desktop_root_window_host_->GetInputMethodDelegate(); + return this; } void DesktopNativeWidgetAura::CenterWindow(const gfx::Size& size) { @@ -445,6 +468,13 @@ void DesktopNativeWidgetAura::OnBoundsChanged(const gfx::Rect& old_bounds, void DesktopNativeWidgetAura::OnFocus(aura::Window* old_focused_window) { desktop_root_window_host_->OnNativeWidgetFocus(); native_widget_delegate_->OnNativeFocus(old_focused_window); + + // If focus is moving from a descendant Window to |window_| then native + // activation hasn't changed. We still need to inform the InputMethod we've + // been focused though. + InputMethod* input_method = GetWidget()->GetInputMethod(); + if (input_method) + input_method->OnFocus(); } void DesktopNativeWidgetAura::OnBlur() { @@ -592,4 +622,15 @@ void DesktopNativeWidgetAura::OnLostActive() { GetWidget()->non_client_view()->SchedulePaint(); } +//////////////////////////////////////////////////////////////////////////////// +// DesktopNativeWidgetAura, views::internal::InputMethodDelegate: + +void DesktopNativeWidgetAura::DispatchKeyEventPostIME(const ui::KeyEvent& key) { + FocusManager* focus_manager = + native_widget_delegate_->AsWidget()->GetFocusManager(); + if (native_widget_delegate_->OnKeyEvent(key) || !focus_manager) + return; + focus_manager->OnKeyEvent(key); +} + } // namespace views diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h index b3abe0f..63977a5 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h @@ -8,6 +8,7 @@ #include "base/memory/weak_ptr.h" #include "ui/aura/client/activation_delegate.h" #include "ui/aura/window_delegate.h" +#include "ui/views/ime/input_method_delegate.h" #include "ui/views/widget/native_widget_private.h" namespace aura { @@ -19,6 +20,11 @@ class StackingClient; namespace views { +namespace corewm { +class CompoundEventFilter; +class InputMethodEventFilter; +} + class DesktopRootWindowHost; class NativeWidgetAuraWindowObserver; @@ -26,7 +32,8 @@ class NativeWidgetAuraWindowObserver; class VIEWS_EXPORT DesktopNativeWidgetAura : public internal::NativeWidgetPrivate, public aura::WindowDelegate, - public aura::client::ActivationDelegate { + public aura::client::ActivationDelegate, + public views::internal::InputMethodDelegate { public: explicit DesktopNativeWidgetAura(internal::NativeWidgetDelegate* delegate); virtual ~DesktopNativeWidgetAura(); @@ -38,6 +45,16 @@ class VIEWS_EXPORT DesktopNativeWidgetAura // this is the signal that we should start our shutdown. void OnHostClosed(); + // Installs the input method filter on |root|. This is intended to be invoked + // by the DesktopRootWindowHost implementation during Init(). + void InstallInputMethodEventFilter(aura::RootWindow* root); + corewm::InputMethodEventFilter* input_method_event_filter() { + return input_method_event_filter_.get(); + } + corewm::CompoundEventFilter* root_window_event_filter() { + return root_window_event_filter_; + } + protected: // Overridden from internal::NativeWidgetPrivate: virtual void InitNativeWidget(const Widget::InitParams& params) OVERRIDE; @@ -160,6 +177,9 @@ class VIEWS_EXPORT DesktopNativeWidgetAura virtual void OnActivated() OVERRIDE; virtual void OnLostActive() OVERRIDE; + // Overridden from views::internal::InputMethodDelegate: + virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE; + private: // See class documentation for Widget in widget.h for a note about ownership. Widget::InitParams::Ownership ownership_; @@ -184,6 +204,11 @@ class VIEWS_EXPORT DesktopNativeWidgetAura scoped_ptr<aura::client::StackingClient> stacking_client_; + // Toplevel event filter which dispatches to other event filters. + corewm::CompoundEventFilter* root_window_event_filter_; + + scoped_ptr<corewm::InputMethodEventFilter> input_method_event_filter_; + DISALLOW_COPY_AND_ASSIGN(DesktopNativeWidgetAura); }; diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host.h b/ui/views/widget/desktop_aura/desktop_root_window_host.h index bf2655e..b8066e5 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host.h +++ b/ui/views/widget/desktop_aura/desktop_root_window_host.h @@ -26,7 +26,6 @@ class NativeTheme; namespace views { class DesktopNativeWidgetAura; namespace internal { -class InputMethodDelegate; class NativeWidgetDelegate; } @@ -82,9 +81,6 @@ class VIEWS_EXPORT DesktopRootWindowHost { virtual void SetAlwaysOnTop(bool always_on_top) = 0; - virtual InputMethod* CreateInputMethod() = 0; - virtual internal::InputMethodDelegate* GetInputMethodDelegate() = 0; - virtual void SetWindowTitle(const string16& title) = 0; virtual void ClearNativeFocus() = 0; diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc index eab034ca..3d75f77 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc @@ -22,8 +22,6 @@ #include "ui/base/x/x11_util.h" #include "ui/native_theme/native_theme.h" #include "ui/views/corewm/compound_event_filter.h" -#include "ui/views/corewm/input_method_event_filter.h" -#include "ui/views/ime/input_method_bridge.h" #include "ui/views/widget/desktop_aura/desktop_activation_client.h" #include "ui/views/widget/desktop_aura/desktop_cursor_client.h" #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h" @@ -231,20 +229,14 @@ aura::RootWindow* DesktopRootWindowHostLinux::InitRootWindow( aura::client::SetScreenPositionClient(root_window_, position_client_.get()); - // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow. - root_window_event_filter_ = new corewm::CompoundEventFilter; - // Pass ownership of the filter to the root_window. - root_window_->SetEventFilter(root_window_event_filter_); - - input_method_filter_.reset(new corewm::InputMethodEventFilter); - input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_); - root_window_event_filter_->AddHandler(input_method_filter_.get()); + desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_); // TODO(erg): Unify this code once the other consumer goes away. x11_window_event_filter_.reset( new X11WindowEventFilter(root_window_, activation_client_.get())); x11_window_event_filter_->SetUseHostWindowBorders(false); - root_window_event_filter_->AddHandler(x11_window_event_filter_.get()); + desktop_native_widget_aura_->root_window_event_filter()->AddHandler( + x11_window_event_filter_.get()); x11_window_move_client_.reset(new X11DesktopWindowMoveClient); aura::client::SetWindowMoveClient(root_window_, @@ -328,8 +320,8 @@ void DesktopRootWindowHostLinux::Close() { void DesktopRootWindowHostLinux::CloseNow() { // Remove the event listeners we've installed. We need to remove these // because otherwise we get assert during ~RootWindow(). - root_window_event_filter_->RemoveHandler(x11_window_event_filter_.get()); - root_window_event_filter_->RemoveHandler(input_method_filter_.get()); + desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler( + x11_window_event_filter_.get()); // Actually free our native resources. base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); @@ -512,16 +504,6 @@ void DesktopRootWindowHostLinux::SetAlwaysOnTop(bool always_on_top) { NOTIMPLEMENTED(); } -InputMethod* DesktopRootWindowHostLinux::CreateInputMethod() { - ui::InputMethod* host = input_method_filter_->input_method(); - return new InputMethodBridge(this, host); -} - -internal::InputMethodDelegate* - DesktopRootWindowHostLinux::GetInputMethodDelegate() { - return this; -} - void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) { XStoreName(xdisplay_, xwindow_, UTF16ToUTF8(title).c_str()); } @@ -846,18 +828,6 @@ void DesktopRootWindowHostLinux::PrepareForShutdown() { } //////////////////////////////////////////////////////////////////////////////// -// DesktopRootWindowHostLinux, views::internal::InputMethodDelegate: - -void DesktopRootWindowHostLinux::DispatchKeyEventPostIME( - const ui::KeyEvent& key) { - FocusManager* focus_manager = - native_widget_delegate_->AsWidget()->GetFocusManager(); - if (native_widget_delegate_->OnKeyEvent(key) || !focus_manager) - return; - focus_manager->OnKeyEvent(key); -} - -//////////////////////////////////////////////////////////////////////////////// // DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation: bool DesktopRootWindowHostLinux::Dispatch(const base::NativeEvent& event) { diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h index e8748f5..ae5b736d 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h @@ -17,7 +17,6 @@ #include "ui/gfx/rect.h" #include "ui/base/cursor/cursor_loader_x11.h" #include "ui/base/x/x11_atom_cache.h" -#include "ui/views/ime/input_method_delegate.h" #include "ui/views/views_export.h" #include "ui/views/widget/desktop_aura/desktop_root_window_host.h" @@ -35,15 +34,10 @@ class DesktopCursorClient; class DesktopDispatcherClient; class X11DesktopWindowMoveClient; class X11WindowEventFilter; -namespace corewm { -class CompoundEventFilter; -class InputMethodEventFilter; -} class VIEWS_EXPORT DesktopRootWindowHostLinux : public DesktopRootWindowHost, public aura::RootWindowHost, - public views::internal::InputMethodDelegate, public MessageLoop::Dispatcher { public: DesktopRootWindowHostLinux( @@ -122,8 +116,6 @@ class VIEWS_EXPORT DesktopRootWindowHostLinux virtual bool IsMinimized() const OVERRIDE; virtual bool HasCapture() const OVERRIDE; virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE; - virtual InputMethod* CreateInputMethod() OVERRIDE; - virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE; virtual void SetWindowTitle(const string16& title) OVERRIDE; virtual void ClearNativeFocus() OVERRIDE; virtual Widget::MoveLoopResult RunMoveLoop( @@ -174,9 +166,6 @@ class VIEWS_EXPORT DesktopRootWindowHostLinux virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE; virtual void PrepareForShutdown() OVERRIDE; - // Overridden from views::internal::InputMethodDelegate: - virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE; - // Overridden from Dispatcher: virtual bool Dispatch(const base::NativeEvent& event) OVERRIDE; @@ -221,11 +210,6 @@ class VIEWS_EXPORT DesktopRootWindowHostLinux // The invisible cursor. ::Cursor invisible_cursor_; - // Toplevel event filter which dispatches to other event filters. - corewm::CompoundEventFilter* root_window_event_filter_; - - // An event filter that pre-handles all key events to send them to an IME. - scoped_ptr<corewm::InputMethodEventFilter> input_method_filter_; scoped_ptr<X11WindowEventFilter> x11_window_event_filter_; scoped_ptr<X11DesktopWindowMoveClient> x11_window_move_client_; diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc index 3fdaef7..ce4c73b 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc @@ -13,6 +13,7 @@ #include "ui/aura/ui_controls_aura.h" #include "ui/aura/window_property.h" #include "ui/base/cursor/cursor_loader_win.h" +#include "ui/base/ime/input_method_win.h" #include "ui/base/win/shell.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/path_win.h" @@ -21,7 +22,7 @@ #include "ui/ui_controls/ui_controls.h" #include "ui/views/corewm/compound_event_filter.h" #include "ui/views/corewm/input_method_event_filter.h" -#include "ui/views/ime/input_method_win.h" +#include "ui/views/ime/input_method_bridge.h" #include "ui/views/widget/desktop_aura/desktop_activation_client.h" #include "ui/views/widget/desktop_aura/desktop_cursor_client.h" #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h" @@ -134,15 +135,7 @@ aura::RootWindow* DesktopRootWindowHostWin::Init( aura::client::SetScreenPositionClient(root_window_, position_client_.get()); - // CEF sets focus to the window the user clicks down on. - // TODO(beng): see if we can't do this some other way. CEF seems a heavy- - // handed way of accomplishing focus. - root_window_event_filter_ = new views::corewm::CompoundEventFilter; - root_window_->SetEventFilter(root_window_event_filter_); - - input_method_filter_.reset(new views::corewm::InputMethodEventFilter); - input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_); - root_window_event_filter_->AddHandler(input_method_filter_.get()); + desktop_native_widget_aura_->InstallInputMethodEventFilter(root_window_); focus_client_->FocusWindow(content_window_, NULL); root_window_->SetProperty(kContentWindowForRootWindow, content_window_); @@ -258,25 +251,6 @@ void DesktopRootWindowHostWin::SetAlwaysOnTop(bool always_on_top) { message_handler_->SetAlwaysOnTop(always_on_top); } -InputMethod* DesktopRootWindowHostWin::CreateInputMethod() { - // TODO(ime): This is wrong. We need to hook up the native win32 IME on the - // InputMethodEventFilter, and instead create an InputMethodBridge - // per-NativeWidget implementation. Once we achieve that we can get rid of - // this function on this object and DesktopRootWindowHostLinux and just - // create the InputMethodBridge directly in DesktopNativeWidgetAura. Also - // at that time DNWA can become the InputMethodDelegate. - ui::InputMethod* host = - root_window_->GetProperty(aura::client::kRootWindowInputMethodKey); - return new InputMethodWin(message_handler_.get(), - message_handler_->hwnd(), - host); -} - -internal::InputMethodDelegate* - DesktopRootWindowHostWin::GetInputMethodDelegate() { - return message_handler_.get(); -} - void DesktopRootWindowHostWin::SetWindowTitle(const string16& title) { message_handler_->SetTitle(title); } @@ -623,7 +597,6 @@ void DesktopRootWindowHostWin::HandleDestroying() { } void DesktopRootWindowHostWin::HandleDestroyed() { - root_window_event_filter_->RemoveHandler(input_method_filter_.get()); desktop_native_widget_aura_->OnHostClosed(); } @@ -692,29 +665,35 @@ bool DesktopRootWindowHostWin::HandleMouseEvent(const ui::MouseEvent& event) { } bool DesktopRootWindowHostWin::HandleKeyEvent(const ui::KeyEvent& event) { - return root_window_host_delegate_->OnHostKeyEvent( - const_cast<ui::KeyEvent*>(&event)); + // We must return false here so HWNDMessageHandler::DispatchKeyEventPostIME() + // marks the message as not handled. This enables win32 to map things like an + // alt key press to a WM_SYSCHAR for showing a menu. + // NOTE: we get here because HandleIMEMessage() below returns false. We need + // not do anything as HandleIMEMessage already processed the message. + return false; } bool DesktopRootWindowHostWin::HandleUntranslatedKeyEvent( const ui::KeyEvent& event) { - InputMethod* input_method = GetInputMethod(); - if (input_method) - input_method->DispatchKeyEvent(event); - return !!input_method; + scoped_ptr<ui::KeyEvent> duplicate_event(event.Copy()); + static_cast<aura::RootWindowHostDelegate*>(root_window_)->OnHostKeyEvent( + duplicate_event.get()); + // We must return false here so that HWNDMessageHandler invokes + // HandleKeyEvent(). See comment in HandleKeyEvent as to why it's important. + return false; } bool DesktopRootWindowHostWin::HandleIMEMessage(UINT message, - WPARAM w_param, - LPARAM l_param, - LRESULT* result) { - InputMethod* input_method = GetInputMethod(); - if (!input_method || input_method->IsMock()) { - *result = 0; - return false; - } - - InputMethodWin* ime_win = static_cast<InputMethodWin*>(input_method); + WPARAM w_param, + LPARAM l_param, + LRESULT* result) { + // TODO(ime): Having to cast here is wrong. Maybe we should have IME events + // and have these flow through the same path as HandleUntranslatedKeyEvent() + // does. + ui::InputMethodWin* ime_win = + static_cast<ui::InputMethodWin*>( + desktop_native_widget_aura_->input_method_event_filter()-> + input_method()); BOOL handled = FALSE; *result = ime_win->OnImeMessages(message, w_param, l_param, &handled); return !!handled; @@ -723,11 +702,12 @@ bool DesktopRootWindowHostWin::HandleIMEMessage(UINT message, void DesktopRootWindowHostWin::HandleInputLanguageChange( DWORD character_set, HKL input_language_id) { - InputMethod* input_method = GetInputMethod(); - if (input_method && !input_method->IsMock()) { - static_cast<InputMethodWin*>(input_method)->OnInputLangChange( - character_set, input_language_id); - } + // TODO(ime): Seem comment in HandleIMEMessage(). + ui::InputMethodWin* ime_win = + static_cast<ui::InputMethodWin*>( + desktop_native_widget_aura_->input_method_event_filter()-> + input_method()); + ime_win->OnInputLangChange(character_set, input_language_id); } bool DesktopRootWindowHostWin::HandlePaintAccelerated( diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h index 927123b..8ff793c 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h @@ -23,10 +23,6 @@ class DesktopActivationClient; class DesktopCursorClient; class DesktopDispatcherClient; class HWNDMessageHandler; -namespace corewm { -class CompoundEventFilter; -class InputMethodEventFilter; -} class VIEWS_EXPORT DesktopRootWindowHostWin : public DesktopRootWindowHost, @@ -73,8 +69,6 @@ class VIEWS_EXPORT DesktopRootWindowHostWin virtual bool IsMinimized() const OVERRIDE; virtual bool HasCapture() const OVERRIDE; virtual void SetAlwaysOnTop(bool always_on_top) OVERRIDE; - virtual InputMethod* CreateInputMethod() OVERRIDE; - virtual internal::InputMethodDelegate* GetInputMethodDelegate() OVERRIDE; virtual void SetWindowTitle(const string16& title) OVERRIDE; virtual void ClearNativeFocus() OVERRIDE; virtual Widget::MoveLoopResult RunMoveLoop( @@ -213,7 +207,6 @@ class VIEWS_EXPORT DesktopRootWindowHostWin scoped_ptr<aura::client::FocusClient> focus_client_; // Depends on focus_manager_. scoped_ptr<DesktopActivationClient> activation_client_; - scoped_ptr<corewm::InputMethodEventFilter> input_method_filter_; // TODO(beng): Consider providing an interface to DesktopNativeWidgetAura // instead of providing this route back to Widget. @@ -231,9 +224,6 @@ class VIEWS_EXPORT DesktopRootWindowHostWin // A simple cursor client which just forwards events to the RootWindow. scoped_ptr<DesktopCursorClient> cursor_client_; - // The RootWindow's CompoundEventFilter. - views::corewm::CompoundEventFilter* root_window_event_filter_; - DISALLOW_COPY_AND_ASSIGN(DesktopRootWindowHostWin); }; diff --git a/ui/views/widget/desktop_aura/desktop_stacking_client.cc b/ui/views/widget/desktop_aura/desktop_stacking_client.cc index 46ffe9c..e26f478 100644 --- a/ui/views/widget/desktop_aura/desktop_stacking_client.cc +++ b/ui/views/widget/desktop_aura/desktop_stacking_client.cc @@ -49,7 +49,8 @@ void DesktopStackingClient::CreateNULLParent() { window_event_filter_ = new corewm::CompoundEventFilter; null_parent_->SetEventFilter(window_event_filter_); - input_method_filter_.reset(new corewm::InputMethodEventFilter); + input_method_filter_.reset(new corewm::InputMethodEventFilter( + null_parent_->GetAcceleratedWidget())); input_method_filter_->SetInputMethodPropertyInRootWindow(null_parent_.get()); window_event_filter_->AddHandler(input_method_filter_.get()); diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 31548af..e11da64 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc @@ -800,20 +800,6 @@ ui::EventResult NativeWidgetAura::OnKeyEvent(ui::KeyEvent* event) { // and the window may be invisible by that time. if (!window_->IsVisible()) return ui::ER_UNHANDLED; -#if defined(OS_WIN) - // Work around for incomplete InputMethod wiring. If we're in a constrained - // window DispatchKeyEvent below results in an infinite loop. Short circuit - // that by invoking DispatchKeyEventIME() directly, which is what - // InputMethodBridge::DispatchKeyEvent does. - // TODO(ime): remove this hack. - if (DesktopRootWindowHostWin::GetContentWindowForHWND( - window_->GetRootWindow()->GetAcceleratedWidget()) && - (event->type() != ui::ET_TRANSLATED_KEY_PRESS && - event->type() != ui::ET_TRANSLATED_KEY_RELEASE)) { - DispatchKeyEventPostIME(*event); - return ui::ER_HANDLED; - } -#endif GetWidget()->GetInputMethod()->DispatchKeyEvent(*event); return ui::ER_HANDLED; } diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index 91718e7..57cbfaf 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -463,7 +463,6 @@ gfx::Rect HWNDMessageHandler::GetClientAreaBoundsInScreen() const { return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top); } - gfx::Rect HWNDMessageHandler::GetRestoredBounds() const { // If we're in fullscreen mode, we've changed the normal bounds to the monitor // rect, so return the saved bounds instead. @@ -1436,7 +1435,6 @@ void HWNDMessageHandler::OnInputLangChange(DWORD character_set, LRESULT HWNDMessageHandler::OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param) { - MSG msg = { hwnd(), message, w_param, l_param }; ui::KeyEvent key(msg, message == WM_CHAR); if (!delegate_->HandleUntranslatedKeyEvent(key)) |