diff options
author | yukawa@chromium.org <yukawa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-11 02:37:21 +0000 |
---|---|---|
committer | yukawa@chromium.org <yukawa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-11 02:37:21 +0000 |
commit | 8be5344d42caeff97ff8eaadf9220fa9383852d1 (patch) | |
tree | 8e364e8ca10ba921cd9940ff1ecaa9261f9f7219 | |
parent | b9612330073aa910a5b998f4cb96ca17c05271fb (diff) | |
download | chromium_src-8be5344d42caeff97ff8eaadf9220fa9383852d1.zip chromium_src-8be5344d42caeff97ff8eaadf9220fa9383852d1.tar.gz chromium_src-8be5344d42caeff97ff8eaadf9220fa9383852d1.tar.bz2 |
Ash: tell the browser process of the LANGID of the active input source
This is a preparation CL to implement 'locale' property proposed in UI Events (formerly called d4e).
http://www.w3.org/TR/uievents/#idl-def-KeyboardEventInit
On Windows 8/8.1, a user can still choose per-process IME/keyboard layout model. Thus, we need to tell the browser process what IME/keyboard layout is used in the metro_driver process whenever it is changed.
BUG=168971
TEST=manually done on Windows 8.1
Review URL: https://codereview.chromium.org/109683002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239971 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/aura/remote_root_window_host_win.cc | 11 | ||||
-rw-r--r-- | ui/aura/remote_root_window_host_win.h | 1 | ||||
-rw-r--r-- | win8/metro_driver/chrome_app_view_ash.cc | 23 | ||||
-rw-r--r-- | win8/metro_driver/chrome_app_view_ash.h | 7 | ||||
-rw-r--r-- | win8/metro_driver/ime/ime.gypi | 3 | ||||
-rw-r--r-- | win8/metro_driver/ime/input_source.cc | 170 | ||||
-rw-r--r-- | win8/metro_driver/ime/input_source.h | 36 | ||||
-rw-r--r-- | win8/metro_driver/ime/input_source_observer.h | 26 |
8 files changed, 277 insertions, 0 deletions
diff --git a/ui/aura/remote_root_window_host_win.cc b/ui/aura/remote_root_window_host_win.cc index 35dc3a0..f6de429 100644 --- a/ui/aura/remote_root_window_host_win.cc +++ b/ui/aura/remote_root_window_host_win.cc @@ -221,6 +221,8 @@ bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) { OnImeCompositionChanged) IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeTextCommitted, OnImeTextCommitted) + IPC_MESSAGE_HANDLER(MetroViewerHostMsg_ImeInputSourceChanged, + OnImeInputSourceChanged) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -674,6 +676,15 @@ void RemoteRootWindowHostWin::OnImeTextCommitted(const string16& text) { remote_input_method_private->OnTextCommitted(text); } +void RemoteRootWindowHostWin::OnImeInputSourceChanged(uint16 language_id, + bool is_ime) { + ui::RemoteInputMethodPrivateWin* remote_input_method_private = + GetRemoteInputMethodPrivate(); + if (!remote_input_method_private) + return; + remote_input_method_private->OnInputSourceChanged(language_id, is_ime); +} + void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type, uint32 vkey, uint32 repeat_count, diff --git a/ui/aura/remote_root_window_host_win.h b/ui/aura/remote_root_window_host_win.h index 04bd6bc..a319d27 100644 --- a/ui/aura/remote_root_window_host_win.h +++ b/ui/aura/remote_root_window_host_win.h @@ -205,6 +205,7 @@ class AURA_EXPORT RemoteRootWindowHostWin int32 selection_end, const std::vector<metro_viewer::UnderlineInfo>& underlines); void OnImeTextCommitted(const string16& text); + void OnImeInputSourceChanged(uint16 language_id, bool is_ime); // RootWindowHost overrides: virtual RootWindow* GetRootWindow() OVERRIDE; diff --git a/win8/metro_driver/chrome_app_view_ash.cc b/win8/metro_driver/chrome_app_view_ash.cc index 2e96a00..e6525d1 100644 --- a/win8/metro_driver/chrome_app_view_ash.cc +++ b/win8/metro_driver/chrome_app_view_ash.cc @@ -24,6 +24,7 @@ #include "ui/events/gestures/gesture_sequence.h" #include "ui/metro_viewer/metro_viewer_messages.h" #include "win8/metro_driver/file_picker_ash.h" +#include "win8/metro_driver/ime/input_source.h" #include "win8/metro_driver/ime/text_service.h" #include "win8/metro_driver/metro_driver.h" #include "win8/metro_driver/winrt_utils.h" @@ -632,6 +633,13 @@ ChromeAppViewAsh::Run() { new MetroViewerHostMsg_WindowSizeChanged(rect.right - rect.left, rect.bottom - rect.top)); + input_source_ = metro_driver::InputSource::Create(); + if (input_source_) { + input_source_->AddObserver(this); + // Send an initial input source. + OnInputSourceChanged(); + } + // And post the task that'll do the inner Metro message pumping to it. ui_loop_.PostTask(FROM_HERE, base::Bind(&RunMessageLoop, dispatcher.Get())); ui_loop_.Run(); @@ -643,6 +651,7 @@ ChromeAppViewAsh::Run() { IFACEMETHODIMP ChromeAppViewAsh::Uninitialize() { DVLOG(1) << __FUNCTION__; + input_source_.reset(); text_service_.reset(); window_ = nullptr; view_ = nullptr; @@ -835,6 +844,20 @@ void ChromeAppViewAsh::OnImeUpdateTextInputClient( text_service_->OnDocumentChanged(input_scopes, character_bounds); } +void ChromeAppViewAsh::OnInputSourceChanged() { + if (!input_source_) + return; + + LANGID langid = 0; + bool is_ime = false; + if (!input_source_->GetActiveSource(&langid, &is_ime)) { + LOG(ERROR) << "GetActiveSource failed"; + return; + } + ui_channel_->Send(new MetroViewerHostMsg_ImeInputSourceChanged(langid, + is_ime)); +} + void ChromeAppViewAsh::OnCompositionChanged( const string16& text, int32 selection_start, diff --git a/win8/metro_driver/chrome_app_view_ash.h b/win8/metro_driver/chrome_app_view_ash.h index c2e6d42..7517502 100644 --- a/win8/metro_driver/chrome_app_view_ash.h +++ b/win8/metro_driver/chrome_app_view_ash.h @@ -15,6 +15,7 @@ #include "base/strings/string16.h" #include "ui/events/event_constants.h" #include "win8/metro_driver/direct3d_helper.h" +#include "win8/metro_driver/ime/input_source_observer.h" #include "win8/metro_driver/ime/text_service_delegate.h" namespace base { @@ -27,6 +28,7 @@ class ChannelProxy; } namespace metro_driver { +class InputSource; class TextService; } @@ -44,6 +46,7 @@ struct MetroViewerHostMsg_SaveAsDialogParams; class ChromeAppViewAsh : public mswr::RuntimeClass<winapp::Core::IFrameworkView>, + public metro_driver::InputSourceObserver, public metro_driver::TextServiceDelegate { public: ChromeAppViewAsh(); @@ -102,6 +105,9 @@ class ChromeAppViewAsh private: + // InputSourceObserver overrides. + virtual void OnInputSourceChanged() OVERRIDE; + // TextServiceDelegate overrides. virtual void OnCompositionChanged( const string16& text, @@ -190,6 +196,7 @@ class ChromeAppViewAsh base::MessageLoop ui_loop_; // For IME support. + scoped_ptr<metro_driver::InputSource> input_source_; scoped_ptr<metro_driver::TextService> text_service_; }; diff --git a/win8/metro_driver/ime/ime.gypi b/win8/metro_driver/ime/ime.gypi index c5d7f1e..f787f2a 100644 --- a/win8/metro_driver/ime/ime.gypi +++ b/win8/metro_driver/ime/ime.gypi @@ -6,6 +6,9 @@ 'sources': [ 'input_scope.cc', 'input_scope.h', + 'input_source.cc', + 'input_source.h', + 'input_source_observer.h', 'text_service.cc', 'text_service.h', 'text_service_delegate.h', diff --git a/win8/metro_driver/ime/input_source.cc b/win8/metro_driver/ime/input_source.cc new file mode 100644 index 0000000..dd27380 --- /dev/null +++ b/win8/metro_driver/ime/input_source.cc @@ -0,0 +1,170 @@ +// Copyright 2013 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 "win8/metro_driver/ime/input_source.h" + +#include <atlbase.h> +#include <atlcom.h> +#include <msctf.h> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/observer_list.h" +#include "base/win/scoped_comptr.h" +#include "ui/base/win/atl_module.h" +#include "win8/metro_driver/ime/input_source_observer.h" + +namespace metro_driver { +namespace { + +// An implementation of ITfLanguageProfileNotifySink interface, which will be +// used to receive notifications when the text input source is changed. +class ATL_NO_VTABLE InputSourceMonitor + : public CComObjectRootEx<CComMultiThreadModel>, + public ITfLanguageProfileNotifySink { + public: + InputSourceMonitor() + : cookie_(TF_INVALID_COOKIE) { + } + + BEGIN_COM_MAP(InputSourceMonitor) + COM_INTERFACE_ENTRY(ITfLanguageProfileNotifySink) + END_COM_MAP() + + bool Initialize(ITfSource* source) { + DWORD cookie = TF_INVALID_COOKIE; + HRESULT hr = source->AdviseSink(IID_ITfLanguageProfileNotifySink, + this, + &cookie); + if (FAILED(hr)) { + LOG(ERROR) << "ITfSource::AdviseSink failed. hr = " << hr; + return false; + } + cookie_ = cookie; + source_ = source; + return true; + } + + void SetCallback(base::Closure on_language_chanaged) { + on_language_chanaged_ = on_language_chanaged; + } + + void Unadvise() { + if (cookie_ == TF_INVALID_COOKIE || !source_) + return; + if (FAILED(source_->UnadviseSink(cookie_))) + return; + cookie_ = TF_INVALID_COOKIE; + source_.Release(); + } + + private: + // ITfLanguageProfileNotifySink overrides: + STDMETHOD(OnLanguageChange)(LANGID langid, BOOL *accept) OVERRIDE { + if (!accept) + return E_INVALIDARG; + *accept = TRUE; + return S_OK; + } + + STDMETHOD(OnLanguageChanged)() OVERRIDE { + if (!on_language_chanaged_.is_null()) + on_language_chanaged_.Run(); + return S_OK; + } + + base::Closure on_language_chanaged_; + base::win::ScopedComPtr<ITfSource> source_; + DWORD cookie_; + + DISALLOW_COPY_AND_ASSIGN(InputSourceMonitor); +}; + +class InputSourceImpl : public InputSource { + public: + InputSourceImpl(ITfInputProcessorProfileMgr* profile_manager, + InputSourceMonitor* monitor) + : profile_manager_(profile_manager), + monitor_(monitor) { + monitor_->SetCallback(base::Bind(&InputSourceImpl::OnLanguageChanged, + base::Unretained(this))); + } + virtual ~InputSourceImpl() { + monitor_->SetCallback(base::Closure()); + monitor_->Unadvise(); + } + + private: + // InputSource overrides. + virtual bool GetActiveSource(LANGID* langid, bool* is_ime) OVERRIDE { + TF_INPUTPROCESSORPROFILE profile = {}; + HRESULT hr = profile_manager_->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, + &profile); + if (FAILED(hr)) { + LOG(ERROR) << "ITfInputProcessorProfileMgr::GetActiveProfile failed." + << " hr = " << hr; + return false; + } + *langid = profile.langid; + *is_ime = profile.dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR; + return true; + } + virtual void AddObserver(InputSourceObserver* observer) OVERRIDE { + observer_list_.AddObserver(observer); + } + virtual void RemoveObserver(InputSourceObserver* observer) OVERRIDE { + observer_list_.RemoveObserver(observer); + } + void OnLanguageChanged() { + FOR_EACH_OBSERVER(InputSourceObserver, + observer_list_, + OnInputSourceChanged()); + } + + base::win::ScopedComPtr<ITfInputProcessorProfileMgr> profile_manager_; + scoped_refptr<InputSourceMonitor> monitor_; + ObserverList<InputSourceObserver> observer_list_; + + DISALLOW_COPY_AND_ASSIGN(InputSourceImpl); +}; + +} // namespace + +// static +scoped_ptr<InputSource> InputSource::Create() { + ui::win::CreateATLModuleIfNeeded(); + + base::win::ScopedComPtr<ITfInputProcessorProfileMgr> profile_manager; + HRESULT hr = profile_manager.CreateInstance(CLSID_TF_InputProcessorProfiles); + if (FAILED(hr)) { + LOG(ERROR) << "Failed to instantiate CLSID_TF_InputProcessorProfiles." + << " hr = " << hr; + return scoped_ptr<InputSource>(); + } + base::win::ScopedComPtr<ITfSource> profiles_source; + hr = profiles_source.QueryFrom(profile_manager); + if (FAILED(hr)) { + LOG(ERROR) << "QueryFrom to ITfSource failed. hr = " << hr; + return scoped_ptr<InputSource>(); + } + + CComObject<InputSourceMonitor>* monitor = NULL; + hr = CComObject<InputSourceMonitor>::CreateInstance(&monitor); + if (FAILED(hr)) { + LOG(ERROR) << "CComObject<InputSourceMonitor>::CreateInstance failed." + << " hr = " << hr; + return scoped_ptr<InputSource>(); + } + if (!monitor->Initialize(profiles_source)) { + LOG(ERROR) << "Failed to initialize the monitor."; + return scoped_ptr<InputSource>(); + } + + // Transfer the ownership. + return scoped_ptr<InputSource>(new InputSourceImpl(profile_manager, monitor)); +} + +} // namespace metro_driver diff --git a/win8/metro_driver/ime/input_source.h b/win8/metro_driver/ime/input_source.h new file mode 100644 index 0000000..8b057b2 --- /dev/null +++ b/win8/metro_driver/ime/input_source.h @@ -0,0 +1,36 @@ +// Copyright 2013 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 WIN8_METRO_DRIVER_IME_INPUT_SOURCE_H_ +#define WIN8_METRO_DRIVER_IME_INPUT_SOURCE_H_ + +#include <Windows.h> + +#include "base/memory/scoped_ptr.h" + +namespace metro_driver { + +class InputSourceObserver; + +// An interface through which information about the input source can be +// retrieved, where an input source represents an IME or a keyboard layout. +class InputSource { + public: + virtual ~InputSource() {} + // Create an instance. Returns NULL if fails. + static scoped_ptr<InputSource> Create(); + + // Returns true if |langid| and |is_ime| are filled based on the current + // active input source. + virtual bool GetActiveSource(LANGID* langid, bool* is_ime) = 0; + + // Adds/Removes an observer to receive notifications when the active input + // source is changed. + virtual void AddObserver(InputSourceObserver* observer) = 0; + virtual void RemoveObserver(InputSourceObserver* observer) = 0; +}; + +} // namespace metro_driver + +#endif // WIN8_METRO_DRIVER_IME_INPUT_SOURCE_H_ diff --git a/win8/metro_driver/ime/input_source_observer.h b/win8/metro_driver/ime/input_source_observer.h new file mode 100644 index 0000000..4be77a5 --- /dev/null +++ b/win8/metro_driver/ime/input_source_observer.h @@ -0,0 +1,26 @@ +// Copyright 2013 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 WIN8_METRO_DRIVER_IME_INPUT_SOURCE_OBSERVER_H_ +#define WIN8_METRO_DRIVER_IME_INPUT_SOURCE_OBSERVER_H_ + +#include <Windows.h> + +#include "base/basictypes.h" + +namespace metro_driver { + +// An observer interface implemented by objects that want to be informed +// when the active language profile is changed. +class InputSourceObserver { + public: + virtual ~InputSourceObserver() {} + + // Called when the active language profile is changed. + virtual void OnInputSourceChanged() = 0; +}; + +} // namespace metro_driver + +#endif // WIN8_METRO_DRIVER_IME_INPUT_SOURCE_OBSERVER_H_ |