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 "chrome/browser/browser_process.h"
17 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
18 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
19 #include "chrome/browser/chromeos/input_method/input_method_engine.h"
20 #include "chrome/browser/chromeos/language_preferences.h"
21 #include "chromeos/ime/component_extension_ime_manager.h"
22 #include "chromeos/ime/extension_ime_util.h"
23 #include "chromeos/ime/input_method_delegate.h"
24 #include "chromeos/ime/xkeyboard.h"
25 #include "third_party/icu/source/common/unicode/uloc.h"
26 #include "ui/base/accelerators/accelerator.h"
29 namespace input_method
{
33 const char nacl_mozc_jp_id
[] =
34 "_comp_ime_fpfbhcjppmaeaijcidgiibchfbnhbeljnacl_mozc_jp";
36 bool Contains(const std::vector
<std::string
>& container
,
37 const std::string
& value
) {
38 return std::find(container
.begin(), container
.end(), value
) !=
44 bool InputMethodManagerImpl::IsLoginKeyboard(
45 const std::string
& layout
) const {
46 const InputMethodDescriptor
* ime
=
47 util_
.GetInputMethodDescriptorFromId(layout
);
48 return ime
? ime
->is_login_keyboard() : false;
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::EnableLayouts(const std::string
& language_code
,
163 const std::string
& initial_layout
) {
164 if (state_
== STATE_TERMINATING
)
167 std::vector
<std::string
> candidates
;
168 // Add input methods associated with the language.
169 util_
.GetInputMethodIdsFromLanguageCode(language_code
,
170 kKeyboardLayoutsOnly
,
172 // Add the hardware keyboard as well. We should always add this so users
173 // can use the hardware keyboard on the login screen and the screen locker.
174 candidates
.push_back(util_
.GetHardwareInputMethodId());
176 std::vector
<std::string
> layouts
;
177 // First, add the initial input method ID, if it's requested, to
178 // layouts, so it appears first on the list of active input
179 // methods at the input language status menu.
180 if (util_
.IsValidInputMethodId(initial_layout
) &&
181 IsLoginKeyboard(initial_layout
)) {
182 layouts
.push_back(initial_layout
);
183 } else if (!initial_layout
.empty()) {
184 DVLOG(1) << "EnableLayouts: ignoring non-keyboard or invalid ID: "
188 // Add candidates to layouts, while skipping duplicates.
189 for (size_t i
= 0; i
< candidates
.size(); ++i
) {
190 const std::string
& candidate
= candidates
[i
];
191 // Not efficient, but should be fine, as the two vectors are very
192 // short (2-5 items).
193 if (!Contains(layouts
, candidate
) && IsLoginKeyboard(candidate
))
194 layouts
.push_back(candidate
);
197 active_input_method_ids_
.swap(layouts
);
199 // Initialize candidate window controller and widgets such as
200 // candidate window, infolist and mode indicator. Note, mode
201 // indicator is used by only keyboard layout input methods.
202 if (active_input_method_ids_
.size() > 1)
203 MaybeInitializeCandidateWindowController();
205 ChangeInputMethod(initial_layout
); // you can pass empty |initial_layout|.
208 // Adds new input method to given list.
209 bool InputMethodManagerImpl::EnableInputMethodImpl(
210 const std::string
& input_method_id
,
211 std::vector
<std::string
>* new_active_input_method_ids
) const {
212 DCHECK(new_active_input_method_ids
);
213 if (!util_
.IsValidInputMethodId(input_method_id
)) {
214 DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id
;
218 if (!Contains(*new_active_input_method_ids
, input_method_id
))
219 new_active_input_method_ids
->push_back(input_method_id
);
224 // Starts or stops the system input method framework as needed.
225 void InputMethodManagerImpl::ReconfigureIMFramework() {
226 if (component_extension_ime_manager_
->IsInitialized())
227 LoadNecessaryComponentExtensions();
229 const bool need_engine
=
230 !ContainsOnlyKeyboardLayout(active_input_method_ids_
);
232 // Initialize candidate window controller and widgets such as
233 // candidate window, infolist and mode indicator. Note, mode
234 // indicator is used by only keyboard layout input methods.
235 if (need_engine
|| active_input_method_ids_
.size() > 1)
236 MaybeInitializeCandidateWindowController();
239 bool InputMethodManagerImpl::EnableInputMethod(
240 const std::string
& input_method_id
) {
241 if (!EnableInputMethodImpl(input_method_id
, &active_input_method_ids_
))
244 ReconfigureIMFramework();
248 bool InputMethodManagerImpl::EnableInputMethods(
249 const std::vector
<std::string
>& new_active_input_method_ids
) {
250 if (state_
== STATE_TERMINATING
)
253 // Filter unknown or obsolete IDs.
254 std::vector
<std::string
> new_active_input_method_ids_filtered
;
256 for (size_t i
= 0; i
< new_active_input_method_ids
.size(); ++i
)
257 EnableInputMethodImpl(new_active_input_method_ids
[i
],
258 &new_active_input_method_ids_filtered
);
260 if (new_active_input_method_ids_filtered
.empty()) {
261 DVLOG(1) << "EnableInputMethods: No valid input method ID";
265 // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to
266 // keep relative order of the extension input method IDs.
267 for (size_t i
= 0; i
< active_input_method_ids_
.size(); ++i
) {
268 const std::string
& input_method_id
= active_input_method_ids_
[i
];
269 if (extension_ime_util::IsExtensionIME(input_method_id
))
270 new_active_input_method_ids_filtered
.push_back(input_method_id
);
272 active_input_method_ids_
.swap(new_active_input_method_ids_filtered
);
274 ReconfigureIMFramework();
276 // If |current_input_method| is no longer in |active_input_method_ids_|,
277 // ChangeInputMethod() picks the first one in |active_input_method_ids_|.
278 ChangeInputMethod(current_input_method_
.id());
282 void InputMethodManagerImpl::ChangeInputMethod(
283 const std::string
& input_method_id
) {
284 ChangeInputMethodInternal(input_method_id
, false);
287 bool InputMethodManagerImpl::ChangeInputMethodInternal(
288 const std::string
& input_method_id
,
290 if (state_
== STATE_TERMINATING
)
293 std::string input_method_id_to_switch
= input_method_id
;
296 if (!InputMethodIsActivated(input_method_id
)) {
297 scoped_ptr
<InputMethodDescriptors
> input_methods(GetActiveInputMethods());
298 DCHECK(!input_methods
->empty());
299 input_method_id_to_switch
= input_methods
->at(0).id();
300 if (!input_method_id
.empty()) {
301 DVLOG(1) << "Can't change the current input method to "
302 << input_method_id
<< " since the engine is not enabled. "
303 << "Switch to " << input_method_id_to_switch
<< " instead.";
307 if (!component_extension_ime_manager_
->IsInitialized() &&
308 !InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch
)) {
309 // We can't change input method before the initialization of
310 // component extension ime manager. ChangeInputMethod will be
311 // called with |pending_input_method_| when the initialization is
313 pending_input_method_
= input_method_id_to_switch
;
316 pending_input_method_
.clear();
318 // Hide candidate window and info list.
319 if (candidate_window_controller_
.get())
320 candidate_window_controller_
->Hide();
322 // Disable the current engine handler.
323 IBusEngineHandlerInterface
* engine
=
324 IBusBridge::Get()->GetCurrentEngineHandler();
328 // Configure the next engine handler.
329 if (InputMethodUtil::IsKeyboardLayout(input_method_id_to_switch
)) {
330 IBusBridge::Get()->SetCurrentEngineHandler(NULL
);
332 IBusEngineHandlerInterface
* next_engine
=
333 IBusBridge::Get()->SetCurrentEngineHandlerById(
334 input_method_id_to_switch
);
337 next_engine
->Enable();
340 // TODO(komatsu): Check if it is necessary to perform the above routine
341 // when the current input method is equal to |input_method_id_to_swich|.
342 if (current_input_method_
.id() != input_method_id_to_switch
) {
343 // Clear property list. Property list would be updated by
344 // extension IMEs via InputMethodEngine::(Set|Update)MenuItems.
345 // If the current input method is a keyboard layout, empty
346 // properties are sufficient.
347 const InputMethodPropertyList empty_property_list
;
348 SetCurrentInputMethodProperties(empty_property_list
);
350 const InputMethodDescriptor
* descriptor
= NULL
;
351 if (extension_ime_util::IsExtensionIME(input_method_id_to_switch
)) {
352 DCHECK(extra_input_methods_
.find(input_method_id_to_switch
) !=
353 extra_input_methods_
.end());
354 descriptor
= &(extra_input_methods_
[input_method_id_to_switch
]);
357 util_
.GetInputMethodDescriptorFromId(input_method_id_to_switch
);
361 previous_input_method_
= current_input_method_
;
362 current_input_method_
= *descriptor
;
365 // Change the keyboard layout to a preferred layout for the input method.
366 if (!xkeyboard_
->SetCurrentKeyboardLayoutByName(
367 current_input_method_
.GetPreferredKeyboardLayout())) {
368 LOG(ERROR
) << "Failed to change keyboard layout to "
369 << current_input_method_
.GetPreferredKeyboardLayout();
372 // Update input method indicators (e.g. "US", "DV") in Chrome windows.
373 FOR_EACH_OBSERVER(InputMethodManager::Observer
,
375 InputMethodChanged(this, show_message
));
379 void InputMethodManagerImpl::OnComponentExtensionInitialized(
380 scoped_ptr
<ComponentExtensionIMEManagerDelegate
> delegate
) {
381 DCHECK(thread_checker_
.CalledOnValidThread());
382 component_extension_ime_manager_
->Initialize(delegate
.Pass());
383 util_
.SetComponentExtensions(
384 component_extension_ime_manager_
->GetAllIMEAsInputMethodDescriptor());
386 LoadNecessaryComponentExtensions();
388 if (!pending_input_method_
.empty())
389 ChangeInputMethodInternal(pending_input_method_
, false);
393 void InputMethodManagerImpl::LoadNecessaryComponentExtensions() {
394 if (!component_extension_ime_manager_
->IsInitialized())
396 // Load component extensions but also update |active_input_method_ids_| as
397 // some component extension IMEs may have been removed from the Chrome OS
398 // image. If specified component extension IME no longer exists, falling back
399 // to an existing IME.
400 std::vector
<std::string
> unfiltered_input_method_ids
=
401 active_input_method_ids_
;
402 active_input_method_ids_
.clear();
403 for (size_t i
= 0; i
< unfiltered_input_method_ids
.size(); ++i
) {
404 if (!extension_ime_util::IsComponentExtensionIME(
405 unfiltered_input_method_ids
[i
])) {
406 // Legacy IMEs or xkb layouts are alwayes active.
407 active_input_method_ids_
.push_back(unfiltered_input_method_ids
[i
]);
408 } else if (component_extension_ime_manager_
->IsWhitelisted(
409 unfiltered_input_method_ids
[i
])) {
410 component_extension_ime_manager_
->LoadComponentExtensionIME(
411 unfiltered_input_method_ids
[i
]);
412 active_input_method_ids_
.push_back(unfiltered_input_method_ids
[i
]);
417 void InputMethodManagerImpl::ActivateInputMethodProperty(
418 const std::string
& key
) {
419 DCHECK(!key
.empty());
421 for (size_t i
= 0; i
< property_list_
.size(); ++i
) {
422 if (property_list_
[i
].key
== key
) {
423 IBusEngineHandlerInterface
* engine
=
424 IBusBridge::Get()->GetCurrentEngineHandler();
426 engine
->PropertyActivate(key
);
431 DVLOG(1) << "ActivateInputMethodProperty: unknown key: " << key
;
434 void InputMethodManagerImpl::AddInputMethodExtension(
435 const std::string
& id
,
436 InputMethodEngineInterface
* engine
) {
437 if (state_
== STATE_TERMINATING
)
440 if (!extension_ime_util::IsExtensionIME(id
) &&
441 !extension_ime_util::IsComponentExtensionIME(id
)) {
442 DVLOG(1) << id
<< " is not a valid extension input method ID.";
448 const InputMethodDescriptor
& descriptor
= engine
->GetDescriptor();
449 extra_input_methods_
[id
] = descriptor
;
450 if (Contains(enabled_extension_imes_
, id
) &&
451 !extension_ime_util::IsComponentExtensionIME(id
)) {
452 if (!Contains(active_input_method_ids_
, id
)) {
453 active_input_method_ids_
.push_back(id
);
455 DVLOG(1) << "AddInputMethodExtension: alread added: "
456 << id
<< ", " << descriptor
.name();
457 // Call Start() anyway, just in case.
460 // Ensure that the input method daemon is running.
461 MaybeInitializeCandidateWindowController();
464 IBusBridge::Get()->SetEngineHandler(id
, engine
);
467 void InputMethodManagerImpl::RemoveInputMethodExtension(const std::string
& id
) {
468 if (!extension_ime_util::IsExtensionIME(id
))
469 DVLOG(1) << id
<< " is not a valid extension input method ID.";
471 std::vector
<std::string
>::iterator i
= std::find(
472 active_input_method_ids_
.begin(), active_input_method_ids_
.end(), id
);
473 if (i
!= active_input_method_ids_
.end())
474 active_input_method_ids_
.erase(i
);
475 extra_input_methods_
.erase(id
);
477 // If |current_input_method| is no longer in |active_input_method_ids_|,
478 // switch to the first one in |active_input_method_ids_|.
479 ChangeInputMethod(current_input_method_
.id());
481 if (IBusBridge::Get()->GetCurrentEngineHandler() ==
482 IBusBridge::Get()->GetEngineHandler(id
))
483 IBusBridge::Get()->SetCurrentEngineHandler(NULL
);
486 void InputMethodManagerImpl::GetInputMethodExtensions(
487 InputMethodDescriptors
* result
) {
488 // Build the extension input method descriptors from the extra input
489 // methods cache |extra_input_methods_|.
490 std::map
<std::string
, InputMethodDescriptor
>::iterator iter
;
491 for (iter
= extra_input_methods_
.begin(); iter
!= extra_input_methods_
.end();
493 if (extension_ime_util::IsExtensionIME(iter
->first
))
494 result
->push_back(iter
->second
);
498 void InputMethodManagerImpl::SetEnabledExtensionImes(
499 std::vector
<std::string
>* ids
) {
500 enabled_extension_imes_
.clear();
501 enabled_extension_imes_
.insert(enabled_extension_imes_
.end(),
505 bool active_imes_changed
= false;
507 for (std::map
<std::string
, InputMethodDescriptor
>::iterator extra_iter
=
508 extra_input_methods_
.begin(); extra_iter
!= extra_input_methods_
.end();
510 if (extension_ime_util::IsComponentExtensionIME(
512 continue; // Do not filter component extension.
513 std::vector
<std::string
>::iterator active_iter
= std::find(
514 active_input_method_ids_
.begin(), active_input_method_ids_
.end(),
517 bool active
= active_iter
!= active_input_method_ids_
.end();
518 bool enabled
= Contains(enabled_extension_imes_
, extra_iter
->first
);
520 if (active
&& !enabled
)
521 active_input_method_ids_
.erase(active_iter
);
523 if (!active
&& enabled
)
524 active_input_method_ids_
.push_back(extra_iter
->first
);
526 if (active
== !enabled
)
527 active_imes_changed
= true;
530 if (active_imes_changed
) {
531 MaybeInitializeCandidateWindowController();
533 // If |current_input_method| is no longer in |active_input_method_ids_|,
534 // switch to the first one in |active_input_method_ids_|.
535 ChangeInputMethod(current_input_method_
.id());
539 void InputMethodManagerImpl::SetInputMethodDefault() {
540 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
541 // and US dvorak keyboard layouts.
542 if (g_browser_process
&& g_browser_process
->local_state()) {
543 const std::string locale
= g_browser_process
->GetApplicationLocale();
544 // If the preferred keyboard for the login screen has been saved, use it.
545 PrefService
* prefs
= g_browser_process
->local_state();
546 std::string initial_input_method_id
=
547 prefs
->GetString(chromeos::language_prefs::kPreferredKeyboardLayout
);
548 if (initial_input_method_id
.empty()) {
549 // If kPreferredKeyboardLayout is not specified, use the hardware layout.
550 initial_input_method_id
=
551 GetInputMethodUtil()->GetHardwareInputMethodId();
553 EnableLayouts(locale
, initial_input_method_id
);
557 bool InputMethodManagerImpl::SwitchToNextInputMethod() {
559 if (active_input_method_ids_
.empty()) {
560 DVLOG(1) << "active input method is empty";
564 if (current_input_method_
.id().empty()) {
565 DVLOG(1) << "current_input_method_ is unknown";
569 // Do not consume key event if there is only one input method is enabled.
570 // Ctrl+Space or Alt+Shift may be used by other application.
571 if (active_input_method_ids_
.size() == 1)
574 // Find the next input method and switch to it.
575 SwitchToNextInputMethodInternal(active_input_method_ids_
,
576 current_input_method_
.id());
580 bool InputMethodManagerImpl::SwitchToPreviousInputMethod(
581 const ui::Accelerator
& accelerator
) {
583 if (active_input_method_ids_
.empty()) {
584 DVLOG(1) << "active input method is empty";
588 // Do not consume key event if there is only one input method is enabled.
589 // Ctrl+Space or Alt+Shift may be used by other application.
590 if (active_input_method_ids_
.size() == 1)
593 if (accelerator
.type() == ui::ET_KEY_RELEASED
)
596 if (previous_input_method_
.id().empty() ||
597 previous_input_method_
.id() == current_input_method_
.id()) {
598 return SwitchToNextInputMethod();
601 std::vector
<std::string
>::const_iterator iter
=
602 std::find(active_input_method_ids_
.begin(),
603 active_input_method_ids_
.end(),
604 previous_input_method_
.id());
605 if (iter
== active_input_method_ids_
.end()) {
606 // previous_input_method_ is not supported.
607 return SwitchToNextInputMethod();
609 ChangeInputMethodInternal(*iter
, true);
613 bool InputMethodManagerImpl::SwitchInputMethod(
614 const ui::Accelerator
& accelerator
) {
616 if (active_input_method_ids_
.empty()) {
617 DVLOG(1) << "active input method is empty";
621 // Get the list of input method ids for the |accelerator|. For example, get
622 // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR.
623 std::vector
<std::string
> input_method_ids_to_switch
;
624 switch (accelerator
.key_code()) {
625 case ui::VKEY_CONVERT
: // Henkan key on JP106 keyboard
626 input_method_ids_to_switch
.push_back(nacl_mozc_jp_id
);
628 case ui::VKEY_NONCONVERT
: // Muhenkan key on JP106 keyboard
629 input_method_ids_to_switch
.push_back("xkb:jp::jpn");
631 case ui::VKEY_DBE_SBCSCHAR
: // ZenkakuHankaku key on JP106 keyboard
632 case ui::VKEY_DBE_DBCSCHAR
:
633 input_method_ids_to_switch
.push_back(nacl_mozc_jp_id
);
634 input_method_ids_to_switch
.push_back("xkb:jp::jpn");
640 if (input_method_ids_to_switch
.empty()) {
641 DVLOG(1) << "Unexpected VKEY: " << accelerator
.key_code();
645 // Obtain the intersection of input_method_ids_to_switch and
646 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is
648 std::vector
<std::string
> ids
;
649 for (size_t i
= 0; i
< input_method_ids_to_switch
.size(); ++i
) {
650 const std::string
& id
= input_method_ids_to_switch
[i
];
651 if (Contains(active_input_method_ids_
, id
))
655 // No input method for the accelerator is active. For example, we should
656 // just ignore VKEY_HANGUL when mozc-hangul is not active.
660 SwitchToNextInputMethodInternal(ids
, current_input_method_
.id());
661 return true; // consume the accelerator.
664 void InputMethodManagerImpl::SwitchToNextInputMethodInternal(
665 const std::vector
<std::string
>& input_method_ids
,
666 const std::string
& current_input_method_id
) {
667 std::vector
<std::string
>::const_iterator iter
=
668 std::find(input_method_ids
.begin(),
669 input_method_ids
.end(),
670 current_input_method_id
);
671 if (iter
!= input_method_ids
.end())
673 if (iter
== input_method_ids
.end())
674 iter
= input_method_ids
.begin();
675 ChangeInputMethodInternal(*iter
, true);
678 InputMethodDescriptor
InputMethodManagerImpl::GetCurrentInputMethod() const {
679 if (current_input_method_
.id().empty())
680 return InputMethodUtil::GetFallbackInputMethodDescriptor();
682 return current_input_method_
;
685 InputMethodPropertyList
686 InputMethodManagerImpl::GetCurrentInputMethodProperties() const {
687 // This check is necessary since an IME property (e.g. for Pinyin) might be
688 // sent from ibus-daemon AFTER the current input method is switched to XKB.
689 if (InputMethodUtil::IsKeyboardLayout(GetCurrentInputMethod().id()))
690 return InputMethodPropertyList(); // Empty list.
691 return property_list_
;
694 void InputMethodManagerImpl::SetCurrentInputMethodProperties(
695 const InputMethodPropertyList
& property_list
) {
696 property_list_
= property_list
;
700 XKeyboard
* InputMethodManagerImpl::GetXKeyboard() {
701 return xkeyboard_
.get();
704 InputMethodUtil
* InputMethodManagerImpl::GetInputMethodUtil() {
708 ComponentExtensionIMEManager
*
709 InputMethodManagerImpl::GetComponentExtensionIMEManager() {
710 DCHECK(thread_checker_
.CalledOnValidThread());
711 return component_extension_ime_manager_
.get();
714 void InputMethodManagerImpl::InitializeComponentExtension() {
715 ComponentExtensionIMEManagerImpl
* impl
=
716 new ComponentExtensionIMEManagerImpl();
717 scoped_ptr
<ComponentExtensionIMEManagerDelegate
> delegate(impl
);
718 impl
->InitializeAsync(base::Bind(
719 &InputMethodManagerImpl::OnComponentExtensionInitialized
,
720 weak_ptr_factory_
.GetWeakPtr(),
721 base::Passed(&delegate
)));
724 void InputMethodManagerImpl::Init(base::SequencedTaskRunner
* ui_task_runner
) {
725 DCHECK(thread_checker_
.CalledOnValidThread());
727 xkeyboard_
.reset(XKeyboard::Create());
729 // We can't call impl->Initialize here, because file thread is not available
731 ui_task_runner
->PostTask(
733 base::Bind(&InputMethodManagerImpl::InitializeComponentExtension
,
734 weak_ptr_factory_
.GetWeakPtr()));
737 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting(
738 CandidateWindowController
* candidate_window_controller
) {
739 candidate_window_controller_
.reset(candidate_window_controller
);
740 candidate_window_controller_
->AddObserver(this);
743 void InputMethodManagerImpl::SetXKeyboardForTesting(XKeyboard
* xkeyboard
) {
744 xkeyboard_
.reset(xkeyboard
);
747 void InputMethodManagerImpl::InitializeComponentExtensionForTesting(
748 scoped_ptr
<ComponentExtensionIMEManagerDelegate
> delegate
) {
749 OnComponentExtensionInitialized(delegate
.Pass());
752 void InputMethodManagerImpl::PropertyChanged() {
753 FOR_EACH_OBSERVER(InputMethodManager::Observer
,
755 InputMethodPropertyChanged(this));
758 void InputMethodManagerImpl::CandidateClicked(int index
) {
759 IBusEngineHandlerInterface
* engine
=
760 IBusBridge::Get()->GetCurrentEngineHandler();
762 engine
->CandidateClicked(index
);
765 void InputMethodManagerImpl::CandidateWindowOpened() {
766 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver
,
767 candidate_window_observers_
,
768 CandidateWindowOpened(this));
771 void InputMethodManagerImpl::CandidateWindowClosed() {
772 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver
,
773 candidate_window_observers_
,
774 CandidateWindowClosed(this));
777 void InputMethodManagerImpl::OnScreenLocked() {
778 saved_previous_input_method_
= previous_input_method_
;
779 saved_current_input_method_
= current_input_method_
;
780 saved_active_input_method_ids_
= active_input_method_ids_
;
782 const std::string hardware_keyboard_id
= util_
.GetHardwareInputMethodId();
783 // We'll add the hardware keyboard if it's not included in
784 // |active_input_method_list| so that the user can always use the hardware
785 // keyboard on the screen locker.
786 bool should_add_hardware_keyboard
= true;
788 active_input_method_ids_
.clear();
789 for (size_t i
= 0; i
< saved_active_input_method_ids_
.size(); ++i
) {
790 const std::string
& input_method_id
= saved_active_input_method_ids_
[i
];
791 // Skip if it's not a keyboard layout. Drop input methods including
793 if (!IsLoginKeyboard(input_method_id
))
795 active_input_method_ids_
.push_back(input_method_id
);
796 if (input_method_id
== hardware_keyboard_id
)
797 should_add_hardware_keyboard
= false;
799 if (should_add_hardware_keyboard
)
800 active_input_method_ids_
.push_back(hardware_keyboard_id
);
802 ChangeInputMethod(current_input_method_
.id());
805 void InputMethodManagerImpl::OnScreenUnlocked() {
806 previous_input_method_
= saved_previous_input_method_
;
807 current_input_method_
= saved_current_input_method_
;
808 active_input_method_ids_
= saved_active_input_method_ids_
;
810 ChangeInputMethod(current_input_method_
.id());
813 bool InputMethodManagerImpl::InputMethodIsActivated(
814 const std::string
& input_method_id
) {
815 return Contains(active_input_method_ids_
, input_method_id
);
818 bool InputMethodManagerImpl::ContainsOnlyKeyboardLayout(
819 const std::vector
<std::string
>& value
) {
820 for (size_t i
= 0; i
< value
.size(); ++i
) {
821 if (!InputMethodUtil::IsKeyboardLayout(value
[i
]))
827 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() {
828 if (candidate_window_controller_
.get())
831 candidate_window_controller_
.reset(
832 CandidateWindowController::CreateCandidateWindowController());
833 candidate_window_controller_
->AddObserver(this);
836 } // namespace input_method
837 } // namespace chromeos