1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
7 #include <algorithm> // std::find
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/sys_info.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
19 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
20 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
21 #include "chrome/browser/chromeos/language_preferences.h"
22 #include "chromeos/ime/component_extension_ime_manager.h"
23 #include "chromeos/ime/extension_ime_util.h"
24 #include "chromeos/ime/fake_xkeyboard.h"
25 #include "chromeos/ime/input_method_delegate.h"
26 #include "chromeos/ime/xkeyboard.h"
27 #include "third_party/icu/source/common/unicode/uloc.h"
28 #include "ui/base/accelerators/accelerator.h"
31 namespace input_method {
35 const char nacl_mozc_jp_id[] =
36 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
38 bool Contains(const std::vector<std::string>& container,
39 const std::string& value) {
40 return std::find(container.begin(), container.end(), value) !=
46 bool InputMethodManagerImpl::IsLoginKeyboard(
47 const std::string& layout) const {
48 return util_.IsLoginKeyboard(layout);
51 InputMethodManagerImpl::InputMethodManagerImpl(
52 scoped_ptr<InputMethodDelegate> delegate)
53 : delegate_(delegate.Pass()),
54 state_(STATE_LOGIN_SCREEN),
55 util_(delegate_.get(), GetSupportedInputMethods()),
56 component_extension_ime_manager_(new ComponentExtensionIMEManager()),
57 weak_ptr_factory_(this) {
60 InputMethodManagerImpl::~InputMethodManagerImpl() {
61 if (candidate_window_controller_.get())
62 candidate_window_controller_->RemoveObserver(this);
65 void InputMethodManagerImpl::AddObserver(
66 InputMethodManager::Observer* observer) {
67 observers_.AddObserver(observer);
70 void InputMethodManagerImpl::AddCandidateWindowObserver(
71 InputMethodManager::CandidateWindowObserver* observer) {
72 candidate_window_observers_.AddObserver(observer);
75 void InputMethodManagerImpl::RemoveObserver(
76 InputMethodManager::Observer* observer) {
77 observers_.RemoveObserver(observer);
80 void InputMethodManagerImpl::RemoveCandidateWindowObserver(
81 InputMethodManager::CandidateWindowObserver* observer) {
82 candidate_window_observers_.RemoveObserver(observer);
85 void InputMethodManagerImpl::SetState(State new_state) {
86 const State old_state = state_;
89 case STATE_LOGIN_SCREEN:
91 case STATE_BROWSER_SCREEN:
92 if (old_state == STATE_LOCK_SCREEN)
95 case STATE_LOCK_SCREEN:
98 case STATE_TERMINATING: {
99 if (candidate_window_controller_.get())
100 candidate_window_controller_.reset();
106 scoped_ptr<InputMethodDescriptors>
107 InputMethodManagerImpl::GetSupportedInputMethods() const {
108 return whitelist_.GetSupportedInputMethods();
111 scoped_ptr<InputMethodDescriptors>
112 InputMethodManagerImpl::GetActiveInputMethods() const {
113 scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors);
114 // Build the active input method descriptors from the active input
115 // methods cache |active_input_method_ids_|.
116 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
117 const std::string& input_method_id = active_input_method_ids_[i];
118 const InputMethodDescriptor* descriptor =
119 util_.GetInputMethodDescriptorFromId(input_method_id);
121 result->push_back(*descriptor);
123 std::map<std::string, InputMethodDescriptor>::const_iterator ix =
124 extra_input_methods_.find(input_method_id);
125 if (ix != extra_input_methods_.end())
126 result->push_back(ix->second);
128 DVLOG(1) << "Descriptor is not found for: " << input_method_id;
131 if (result->empty()) {
132 // Initially |active_input_method_ids_| is empty. browser_tests might take
135 InputMethodUtil::GetFallbackInputMethodDescriptor());
137 return result.Pass();
140 const std::vector<std::string>&
141 InputMethodManagerImpl::GetActiveInputMethodIds() const {
142 return active_input_method_ids_;
145 size_t InputMethodManagerImpl::GetNumActiveInputMethods() const {
146 return active_input_method_ids_.size();
149 const InputMethodDescriptor* InputMethodManagerImpl::GetInputMethodFromId(
150 const std::string& input_method_id) const {
151 const InputMethodDescriptor* ime = util_.GetInputMethodDescriptorFromId(
154 std::map<std::string, InputMethodDescriptor>::const_iterator ix =
155 extra_input_methods_.find(input_method_id);
156 if (ix != extra_input_methods_.end())
162 void InputMethodManagerImpl::EnableLoginLayouts(
163 const std::string& language_code,
164 const std::vector<std::string>& initial_layouts) {
165 if (state_ == STATE_TERMINATING)
168 // First, hardware keyboard layout should be shown.
169 std::vector<std::string> candidates =
170 util_.GetHardwareLoginInputMethodIds();
172 // Seocnd, locale based input method should be shown.
173 // Add input methods associated with the language.
174 std::vector<std::string> layouts_from_locale;
175 util_.GetInputMethodIdsFromLanguageCode(language_code,
176 kKeyboardLayoutsOnly,
177 &layouts_from_locale);
178 candidates.insert(candidates.end(), layouts_from_locale.begin(),
179 layouts_from_locale.end());
181 std::vector<std::string> layouts;
182 // First, add the initial input method ID, if it's requested, to
183 // layouts, so it appears first on the list of active input
184 // methods at the input language status menu.
185 for (size_t i = 0; i < initial_layouts.size(); ++i) {
186 if (util_.IsValidInputMethodId(initial_layouts[i])) {
187 if (IsLoginKeyboard(initial_layouts[i])) {
188 layouts.push_back(initial_layouts[i]);
191 << "EnableLoginLayouts: ignoring non-login initial keyboard layout:"
192 << initial_layouts[i];
194 } else if (!initial_layouts[i].empty()) {
195 DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: "
196 << initial_layouts[i];
200 // Add candidates to layouts, while skipping duplicates.
201 for (size_t i = 0; i < candidates.size(); ++i) {
202 const std::string& candidate = candidates[i];
203 // Not efficient, but should be fine, as the two vectors are very
204 // short (2-5 items).
205 if (!Contains(layouts, candidate) && IsLoginKeyboard(candidate))
206 layouts.push_back(candidate);
209 active_input_method_ids_.swap(layouts);
211 // Initialize candidate window controller and widgets such as
212 // candidate window, infolist and mode indicator. Note, mode
213 // indicator is used by only keyboard layout input methods.
214 if (active_input_method_ids_.size() > 1)
215 MaybeInitializeCandidateWindowController();
217 // you can pass empty |initial_layout|.
218 ChangeInputMethod(initial_layouts.empty() ? "" : initial_layouts[0]);
221 // Adds new input method to given list.
222 bool InputMethodManagerImpl::EnableInputMethodImpl(
223 const std::string& input_method_id,
224 std::vector<std::string>* new_active_input_method_ids) const {
225 DCHECK(new_active_input_method_ids);
226 if (!util_.IsValidInputMethodId(input_method_id)) {
227 DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id;
231 if (!Contains(*new_active_input_method_ids, input_method_id))
232 new_active_input_method_ids->push_back(input_method_id);
237 // Starts or stops the system input method framework as needed.
238 void InputMethodManagerImpl::ReconfigureIMFramework() {
239 if (component_extension_ime_manager_->IsInitialized())
240 LoadNecessaryComponentExtensions();
242 const bool need_engine =
243 !ContainsOnlyKeyboardLayout(active_input_method_ids_);
245 // Initialize candidate window controller and widgets such as
246 // candidate window, infolist and mode indicator. Note, mode
247 // indicator is used by only keyboard layout input methods.
248 if (need_engine || active_input_method_ids_.size() > 1)
249 MaybeInitializeCandidateWindowController();
252 bool InputMethodManagerImpl::EnableInputMethod(
253 const std::string& input_method_id) {
254 if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids_))
257 ReconfigureIMFramework();
261 bool InputMethodManagerImpl::ReplaceEnabledInputMethods(
262 const std::vector<std::string>& new_active_input_method_ids) {
263 if (state_ == STATE_TERMINATING)
266 // Filter unknown or obsolete IDs.
267 std::vector<std::string> new_active_input_method_ids_filtered;
269 for (size_t i = 0; i < new_active_input_method_ids.size(); ++i)
270 EnableInputMethodImpl(new_active_input_method_ids[i],
271 &new_active_input_method_ids_filtered);
273 if (new_active_input_method_ids_filtered.empty()) {
274 DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID";
278 // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to
279 // keep relative order of the extension input method IDs.
280 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
281 const std::string& input_method_id = active_input_method_ids_[i];
282 if (extension_ime_util::IsExtensionIME(input_method_id))
283 new_active_input_method_ids_filtered.push_back(input_method_id);
285 active_input_method_ids_.swap(new_active_input_method_ids_filtered);
287 ReconfigureIMFramework();
289 // If |current_input_method| is no longer in |active_input_method_ids_|,
290 // ChangeInputMethod() picks the first one in |active_input_method_ids_|.
291 ChangeInputMethod(current_input_method_.id());
295 void InputMethodManagerImpl::ChangeInputMethod(
296 const std::string& input_method_id) {
297 ChangeInputMethodInternal(input_method_id, false);
300 bool InputMethodManagerImpl::ChangeInputMethodInternal(
301 const std::string& input_method_id,
303 if (state_ == STATE_TERMINATING)
306 std::string input_method_id_to_switch = input_method_id;
309 if (!InputMethodIsActivated(input_method_id)) {
310 scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods());
311 DCHECK(!input_methods->empty());
312 input_method_id_to_switch = input_methods->at(0).id();
313 if (!input_method_id.empty()) {
314 DVLOG(1) << "Can't change the current input method to "
315 << input_method_id << " since the engine is not enabled. "
316 << "Switch to " << input_method_id_to_switch << " instead.";
320 if (!component_extension_ime_manager_->IsInitialized() &&
321 !InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch)) {
322 // We can't change input method before the initialization of
323 // component extension ime manager. ChangeInputMethod will be
324 // called with |pending_input_method_| when the initialization is
326 pending_input_method_ = input_method_id_to_switch;
329 pending_input_method_.clear();
331 // Hide candidate window and info list.
332 if (candidate_window_controller_.get())
333 candidate_window_controller_->Hide();
335 // Disable the current engine handler.
336 IMEEngineHandlerInterface* engine =
337 IMEBridge::Get()->GetCurrentEngineHandler();
341 // Configure the next engine handler.
342 if (InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch)) {
343 IMEBridge::Get()->SetCurrentEngineHandler(NULL);
345 IMEEngineHandlerInterface* next_engine =
346 IMEBridge::Get()->SetCurrentEngineHandlerById(
347 input_method_id_to_switch);
350 next_engine->Enable();
353 // TODO(komatsu): Check if it is necessary to perform the above routine
354 // when the current input method is equal to |input_method_id_to_swich|.
355 if (current_input_method_.id() != input_method_id_to_switch) {
356 // Clear property list. Property list would be updated by
357 // extension IMEs via InputMethodEngine::(Set|Update)MenuItems.
358 // If the current input method is a keyboard layout, empty
359 // properties are sufficient.
360 const InputMethodPropertyList empty_property_list;
361 SetCurrentInputMethodProperties(empty_property_list);
363 const InputMethodDescriptor* descriptor = NULL;
364 if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) {
365 DCHECK(extra_input_methods_.find(input_method_id_to_switch) !=
366 extra_input_methods_.end());
367 descriptor = &(extra_input_methods_[input_method_id_to_switch]);
370 util_.GetInputMethodDescriptorFromId(input_method_id_to_switch);
374 previous_input_method_ = current_input_method_;
375 current_input_method_ = *descriptor;
378 // Change the keyboard layout to a preferred layout for the input method.
379 if (!xkeyboard_->SetCurrentKeyboardLayoutByName(
380 current_input_method_.GetPreferredKeyboardLayout())) {
381 LOG(ERROR) << "Failed to change keyboard layout to "
382 << current_input_method_.GetPreferredKeyboardLayout();
385 // Update input method indicators (e.g. "US", "DV") in Chrome windows.
386 FOR_EACH_OBSERVER(InputMethodManager::Observer,
388 InputMethodChanged(this, show_message));
392 void InputMethodManagerImpl::OnComponentExtensionInitialized(
393 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
394 DCHECK(thread_checker_.CalledOnValidThread());
395 component_extension_ime_manager_->Initialize(delegate.Pass());
396 util_.SetComponentExtensions(
397 component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor());
399 LoadNecessaryComponentExtensions();
401 if (!pending_input_method_.empty())
402 ChangeInputMethodInternal(pending_input_method_, false);
405 void InputMethodManagerImpl::LoadNecessaryComponentExtensions() {
406 if (!component_extension_ime_manager_->IsInitialized())
408 // Load component extensions but also update |active_input_method_ids_| as
409 // some component extension IMEs may have been removed from the Chrome OS
410 // image. If specified component extension IME no longer exists, falling back
411 // to an existing IME.
412 std::vector<std::string> unfiltered_input_method_ids =
413 active_input_method_ids_;
414 active_input_method_ids_.clear();
415 for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) {
416 if (!extension_ime_util::IsComponentExtensionIME(
417 unfiltered_input_method_ids[i])) {
418 // Legacy IMEs or xkb layouts are alwayes active.
419 active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
420 } else if (component_extension_ime_manager_->IsWhitelisted(
421 unfiltered_input_method_ids[i])) {
422 component_extension_ime_manager_->LoadComponentExtensionIME(
423 unfiltered_input_method_ids[i]);
424 active_input_method_ids_.push_back(unfiltered_input_method_ids[i]);
429 void InputMethodManagerImpl::ActivateInputMethodProperty(
430 const std::string& key) {
431 DCHECK(!key.empty());
433 for (size_t i = 0; i < property_list_.size(); ++i) {
434 if (property_list_[i].key == key) {
435 IMEEngineHandlerInterface* engine =
436 IMEBridge::Get()->GetCurrentEngineHandler();
438 engine->PropertyActivate(key);
443 DVLOG(1) << "ActivateInputMethodProperty: unknown key: " << key;
446 void InputMethodManagerImpl::AddInputMethodExtension(
447 const std::string& id,
448 InputMethodEngineInterface* engine) {
449 if (state_ == STATE_TERMINATING)
452 if (!extension_ime_util::IsExtensionIME(id) &&
453 !extension_ime_util::IsComponentExtensionIME(id)) {
454 DVLOG(1) << id << " is not a valid extension input method ID.";
460 const InputMethodDescriptor& descriptor = engine->GetDescriptor();
461 extra_input_methods_[id] = descriptor;
462 if (Contains(enabled_extension_imes_, id) &&
463 !extension_ime_util::IsComponentExtensionIME(id)) {
464 if (!Contains(active_input_method_ids_, id)) {
465 active_input_method_ids_.push_back(id);
467 DVLOG(1) << "AddInputMethodExtension: alread added: "
468 << id << ", " << descriptor.name();
469 // Call Start() anyway, just in case.
472 // Ensure that the input method daemon is running.
473 MaybeInitializeCandidateWindowController();
476 IMEBridge::Get()->SetEngineHandler(id, engine);
479 void InputMethodManagerImpl::RemoveInputMethodExtension(const std::string& id) {
480 if (!extension_ime_util::IsExtensionIME(id))
481 DVLOG(1) << id << " is not a valid extension input method ID.";
483 std::vector<std::string>::iterator i = std::find(
484 active_input_method_ids_.begin(), active_input_method_ids_.end(), id);
485 if (i != active_input_method_ids_.end())
486 active_input_method_ids_.erase(i);
487 extra_input_methods_.erase(id);
489 // If |current_input_method| is no longer in |active_input_method_ids_|,
490 // switch to the first one in |active_input_method_ids_|.
491 ChangeInputMethod(current_input_method_.id());
493 if (IMEBridge::Get()->GetCurrentEngineHandler() ==
494 IMEBridge::Get()->GetEngineHandler(id))
495 IMEBridge::Get()->SetCurrentEngineHandler(NULL);
498 void InputMethodManagerImpl::GetInputMethodExtensions(
499 InputMethodDescriptors* result) {
500 // Build the extension input method descriptors from the extra input
501 // methods cache |extra_input_methods_|.
502 std::map<std::string, InputMethodDescriptor>::iterator iter;
503 for (iter = extra_input_methods_.begin(); iter != extra_input_methods_.end();
505 if (extension_ime_util::IsExtensionIME(iter->first))
506 result->push_back(iter->second);
510 void InputMethodManagerImpl::SetEnabledExtensionImes(
511 std::vector<std::string>* ids) {
512 enabled_extension_imes_.clear();
513 enabled_extension_imes_.insert(enabled_extension_imes_.end(),
517 bool active_imes_changed = false;
519 for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter =
520 extra_input_methods_.begin(); extra_iter != extra_input_methods_.end();
522 if (extension_ime_util::IsComponentExtensionIME(
524 continue; // Do not filter component extension.
525 std::vector<std::string>::iterator active_iter = std::find(
526 active_input_method_ids_.begin(), active_input_method_ids_.end(),
529 bool active = active_iter != active_input_method_ids_.end();
530 bool enabled = Contains(enabled_extension_imes_, extra_iter->first);
532 if (active && !enabled)
533 active_input_method_ids_.erase(active_iter);
535 if (!active && enabled)
536 active_input_method_ids_.push_back(extra_iter->first);
538 if (active == !enabled)
539 active_imes_changed = true;
542 if (active_imes_changed) {
543 MaybeInitializeCandidateWindowController();
545 // If |current_input_method| is no longer in |active_input_method_ids_|,
546 // switch to the first one in |active_input_method_ids_|.
547 ChangeInputMethod(current_input_method_.id());
551 void InputMethodManagerImpl::SetInputMethodLoginDefault() {
552 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
553 // and US dvorak keyboard layouts.
554 if (g_browser_process && g_browser_process->local_state()) {
555 const std::string locale = g_browser_process->GetApplicationLocale();
556 // If the preferred keyboard for the login screen has been saved, use it.
557 PrefService* prefs = g_browser_process->local_state();
558 std::string initial_input_method_id =
559 prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout);
560 std::vector<std::string> input_methods_to_be_enabled;
561 if (initial_input_method_id.empty()) {
562 // If kPreferredKeyboardLayout is not specified, use the hardware layout.
563 input_methods_to_be_enabled = util_.GetHardwareLoginInputMethodIds();
565 input_methods_to_be_enabled.push_back(initial_input_method_id);
567 EnableLoginLayouts(locale, input_methods_to_be_enabled);
571 bool InputMethodManagerImpl::SwitchToNextInputMethod() {
573 if (active_input_method_ids_.empty()) {
574 DVLOG(1) << "active input method is empty";
578 if (current_input_method_.id().empty()) {
579 DVLOG(1) << "current_input_method_ is unknown";
583 // Do not consume key event if there is only one input method is enabled.
584 // Ctrl+Space or Alt+Shift may be used by other application.
585 if (active_input_method_ids_.size() == 1)
588 // Find the next input method and switch to it.
589 SwitchToNextInputMethodInternal(active_input_method_ids_,
590 current_input_method_.id());
594 bool InputMethodManagerImpl::SwitchToPreviousInputMethod(
595 const ui::Accelerator& accelerator) {
597 if (active_input_method_ids_.empty()) {
598 DVLOG(1) << "active input method is empty";
602 // Do not consume key event if there is only one input method is enabled.
603 // Ctrl+Space or Alt+Shift may be used by other application.
604 if (active_input_method_ids_.size() == 1)
607 if (accelerator.type() == ui::ET_KEY_RELEASED)
610 if (previous_input_method_.id().empty() ||
611 previous_input_method_.id() == current_input_method_.id()) {
612 return SwitchToNextInputMethod();
615 std::vector<std::string>::const_iterator iter =
616 std::find(active_input_method_ids_.begin(),
617 active_input_method_ids_.end(),
618 previous_input_method_.id());
619 if (iter == active_input_method_ids_.end()) {
620 // previous_input_method_ is not supported.
621 return SwitchToNextInputMethod();
623 ChangeInputMethodInternal(*iter, true);
627 bool InputMethodManagerImpl::SwitchInputMethod(
628 const ui::Accelerator& accelerator) {
630 if (active_input_method_ids_.empty()) {
631 DVLOG(1) << "active input method is empty";
635 // Get the list of input method ids for the |accelerator|. For example, get
636 // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
637 std::vector<std::string> input_method_ids_to_switch;
638 switch (accelerator.key_code()) {
639 case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard
640 input_method_ids_to_switch.push_back(nacl_mozc_jp_id);
642 case ui::VKEY_NONCONVERT: // Muhenkan key on JP106 keyboard
643 input_method_ids_to_switch.push_back("xkb:jp::jpn");
645 case ui::VKEY_DBE_SBCSCHAR: // ZenkakuHankaku key on JP106 keyboard
646 case ui::VKEY_DBE_DBCSCHAR:
647 input_method_ids_to_switch.push_back(nacl_mozc_jp_id);
648 input_method_ids_to_switch.push_back("xkb:jp::jpn");
654 if (input_method_ids_to_switch.empty()) {
655 DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code();
659 // Obtain the intersection of input_method_ids_to_switch and
660 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is
662 std::vector<std::string> ids;
663 for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) {
664 const std::string& id = input_method_ids_to_switch[i];
665 if (Contains(active_input_method_ids_, id))
669 // No input method for the accelerator is active. For example, we should
670 // just ignore VKEY_HANGUL when mozc-hangul is not active.
674 SwitchToNextInputMethodInternal(ids, current_input_method_.id());
675 return true; // consume the accelerator.
678 void InputMethodManagerImpl::SwitchToNextInputMethodInternal(
679 const std::vector<std::string>& input_method_ids,
680 const std::string& current_input_method_id) {
681 std::vector<std::string>::const_iterator iter =
682 std::find(input_method_ids.begin(),
683 input_method_ids.end(),
684 current_input_method_id);
685 if (iter != input_method_ids.end())
687 if (iter == input_method_ids.end())
688 iter = input_method_ids.begin();
689 ChangeInputMethodInternal(*iter, true);
692 InputMethodDescriptor InputMethodManagerImpl::GetCurrentInputMethod() const {
693 if (current_input_method_.id().empty())
694 return InputMethodUtil::GetFallbackInputMethodDescriptor();
696 return current_input_method_;
699 InputMethodPropertyList
700 InputMethodManagerImpl::GetCurrentInputMethodProperties() const {
701 // This check is necessary since an IME property (e.g. for Pinyin) might be
702 // sent from ibus-daemon AFTER the current input method is switched to XKB.
703 if (InputMethodUtil::IsKeyboardLayout(GetCurrentInputMethod().id()))
704 return InputMethodPropertyList(); // Empty list.
705 return property_list_;
708 void InputMethodManagerImpl::SetCurrentInputMethodProperties(
709 const InputMethodPropertyList& property_list) {
710 property_list_ = property_list;
714 XKeyboard* InputMethodManagerImpl::GetXKeyboard() {
715 return xkeyboard_.get();
718 InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() {
722 ComponentExtensionIMEManager*
723 InputMethodManagerImpl::GetComponentExtensionIMEManager() {
724 DCHECK(thread_checker_.CalledOnValidThread());
725 return component_extension_ime_manager_.get();
728 void InputMethodManagerImpl::InitializeComponentExtension() {
729 ComponentExtensionIMEManagerImpl* impl =
730 new ComponentExtensionIMEManagerImpl();
731 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate(impl);
732 impl->InitializeAsync(base::Bind(
733 &InputMethodManagerImpl::OnComponentExtensionInitialized,
734 weak_ptr_factory_.GetWeakPtr(),
735 base::Passed(&delegate)));
738 void InputMethodManagerImpl::Init(base::SequencedTaskRunner* ui_task_runner) {
739 DCHECK(thread_checker_.CalledOnValidThread());
741 if (base::SysInfo::IsRunningOnChromeOS())
742 xkeyboard_.reset(XKeyboard::Create());
744 xkeyboard_.reset(new FakeXKeyboard());
746 // We can't call impl->Initialize here, because file thread is not available
748 ui_task_runner->PostTask(
750 base::Bind(&InputMethodManagerImpl::InitializeComponentExtension,
751 weak_ptr_factory_.GetWeakPtr()));
754 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
755 CandidateWindowController* candidate_window_controller) {
756 candidate_window_controller_.reset(candidate_window_controller);
757 candidate_window_controller_->AddObserver(this);
760 void InputMethodManagerImpl::SetXKeyboardForTesting(XKeyboard* xkeyboard) {
761 xkeyboard_.reset(xkeyboard);
764 void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
765 scoped_ptr<ComponentExtensionIMEManagerDelegate> delegate) {
766 OnComponentExtensionInitialized(delegate.Pass());
769 void InputMethodManagerImpl::PropertyChanged() {
770 FOR_EACH_OBSERVER(InputMethodManager::Observer,
772 InputMethodPropertyChanged(this));
775 void InputMethodManagerImpl::CandidateClicked(int index) {
776 IMEEngineHandlerInterface* engine =
777 IMEBridge::Get()->GetCurrentEngineHandler();
779 engine->CandidateClicked(index);
782 void InputMethodManagerImpl::CandidateWindowOpened() {
783 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
784 candidate_window_observers_,
785 CandidateWindowOpened(this));
788 void InputMethodManagerImpl::CandidateWindowClosed() {
789 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver,
790 candidate_window_observers_,
791 CandidateWindowClosed(this));
794 void InputMethodManagerImpl::OnScreenLocked() {
795 saved_previous_input_method_ = previous_input_method_;
796 saved_current_input_method_ = current_input_method_;
797 saved_active_input_method_ids_ = active_input_method_ids_;
799 std::set<std::string> added_ids_;
801 const std::vector<std::string>& hardware_keyboard_ids =
802 util_.GetHardwareLoginInputMethodIds();
804 active_input_method_ids_.clear();
805 for (size_t i = 0; i < saved_active_input_method_ids_.size(); ++i) {
806 const std::string& input_method_id = saved_active_input_method_ids_[i];
807 // Skip if it's not a keyboard layout. Drop input methods including
809 if (!IsLoginKeyboard(input_method_id) ||
810 added_ids_.find(input_method_id) != added_ids_.end())
812 active_input_method_ids_.push_back(input_method_id);
813 added_ids_.insert(input_method_id);
816 // We'll add the hardware keyboard if it's not included in
817 // |active_input_method_ids_| so that the user can always use the hardware
818 // keyboard on the screen locker.
819 for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) {
820 if (added_ids_.find(hardware_keyboard_ids[i]) == added_ids_.end()) {
821 active_input_method_ids_.push_back(hardware_keyboard_ids[i]);
822 added_ids_.insert(hardware_keyboard_ids[i]);
826 ChangeInputMethod(current_input_method_.id());
829 void InputMethodManagerImpl::OnScreenUnlocked() {
830 previous_input_method_ = saved_previous_input_method_;
831 current_input_method_ = saved_current_input_method_;
832 active_input_method_ids_ = saved_active_input_method_ids_;
834 ChangeInputMethod(current_input_method_.id());
837 bool InputMethodManagerImpl::InputMethodIsActivated(
838 const std::string& input_method_id) {
839 return Contains(active_input_method_ids_, input_method_id);
842 bool InputMethodManagerImpl::ContainsOnlyKeyboardLayout(
843 const std::vector<std::string>& value) {
844 for (size_t i = 0; i < value.size(); ++i) {
845 if (!InputMethodUtil::IsKeyboardLayout(value[i]))
851 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
852 if (candidate_window_controller_.get())
855 candidate_window_controller_.reset(
856 CandidateWindowController::CreateCandidateWindowController());
857 candidate_window_controller_->AddObserver(this);
860 } // namespace input_method
861 } // namespace chromeos