| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> // std::find | 7 #include <algorithm> // std::find |
| 8 | 8 |
| 9 #include <sstream> |
| 10 |
| 9 #include "ash/ime/input_method_menu_item.h" | 11 #include "ash/ime/input_method_menu_item.h" |
| 10 #include "ash/ime/input_method_menu_manager.h" | 12 #include "ash/ime/input_method_menu_manager.h" |
| 11 #include "base/basictypes.h" | 13 #include "base/basictypes.h" |
| 12 #include "base/bind.h" | 14 #include "base/bind.h" |
| 13 #include "base/location.h" | 15 #include "base/location.h" |
| 14 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/prefs/pref_service.h" | 17 #include "base/prefs/pref_service.h" |
| 16 #include "base/strings/string_split.h" | 18 #include "base/strings/string_split.h" |
| 17 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 18 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 19 #include "base/sys_info.h" | 21 #include "base/sys_info.h" |
| 20 #include "chrome/browser/browser_process.h" | 22 #include "chrome/browser/browser_process.h" |
| 21 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h" | 23 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h" |
| 22 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_i
mpl.h" | 24 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_i
mpl.h" |
| 23 #include "chrome/browser/chromeos/input_method/input_method_engine.h" | 25 #include "chrome/browser/chromeos/input_method/input_method_engine.h" |
| 24 #include "chrome/browser/chromeos/language_preferences.h" | 26 #include "chrome/browser/chromeos/language_preferences.h" |
| 27 #include "chrome/browser/chromeos/login/session/user_session_manager.h" |
| 28 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 25 #include "chrome/browser/profiles/profile_manager.h" | 29 #include "chrome/browser/profiles/profile_manager.h" |
| 26 #include "chrome/common/pref_names.h" | 30 #include "chrome/common/pref_names.h" |
| 27 #include "chromeos/ime/component_extension_ime_manager.h" | 31 #include "chromeos/ime/component_extension_ime_manager.h" |
| 28 #include "chromeos/ime/extension_ime_util.h" | 32 #include "chromeos/ime/extension_ime_util.h" |
| 29 #include "chromeos/ime/fake_ime_keyboard.h" | 33 #include "chromeos/ime/fake_ime_keyboard.h" |
| 30 #include "chromeos/ime/ime_keyboard.h" | 34 #include "chromeos/ime/ime_keyboard.h" |
| 31 #include "chromeos/ime/input_method_delegate.h" | 35 #include "chromeos/ime/input_method_delegate.h" |
| 36 #include "components/user_manager/user_manager.h" |
| 32 #include "third_party/icu/source/common/unicode/uloc.h" | 37 #include "third_party/icu/source/common/unicode/uloc.h" |
| 33 #include "ui/base/accelerators/accelerator.h" | 38 #include "ui/base/accelerators/accelerator.h" |
| 34 | 39 |
| 35 namespace chromeos { | 40 namespace chromeos { |
| 36 namespace input_method { | 41 namespace input_method { |
| 37 | 42 |
| 38 namespace { | 43 namespace { |
| 39 | 44 |
| 40 bool Contains(const std::vector<std::string>& container, | 45 bool Contains(const std::vector<std::string>& container, |
| 41 const std::string& value) { | 46 const std::string& value) { |
| 42 return std::find(container.begin(), container.end(), value) != | 47 return std::find(container.begin(), container.end(), value) != |
| 43 container.end(); | 48 container.end(); |
| 44 } | 49 } |
| 45 | 50 |
| 46 } // namespace | 51 } // namespace |
| 47 | 52 |
| 48 bool InputMethodManagerImpl::IsLoginKeyboard( | 53 // ------------------------ InputMethodManagerImpl::StateImpl |
| 49 const std::string& layout) const { | 54 |
| 50 return util_.IsLoginKeyboard(layout); | 55 InputMethodManagerImpl::StateImpl::StateImpl(InputMethodManagerImpl* manager, |
| 56 Profile* profile) |
| 57 : profile(profile), manager_(manager) { |
| 51 } | 58 } |
| 52 | 59 |
| 53 bool InputMethodManagerImpl::MigrateInputMethods( | 60 InputMethodManagerImpl::StateImpl::~StateImpl() { |
| 54 std::vector<std::string>* input_method_ids) { | |
| 55 return util_.MigrateInputMethods(input_method_ids); | |
| 56 } | 61 } |
| 57 | 62 |
| 58 InputMethodManagerImpl::InputMethodManagerImpl( | 63 void InputMethodManagerImpl::StateImpl::InitFrom(const StateImpl& other) { |
| 59 scoped_ptr<InputMethodDelegate> delegate, bool enable_extension_loading) | 64 previous_input_method = other.previous_input_method; |
| 60 : delegate_(delegate.Pass()), | 65 current_input_method = other.current_input_method; |
| 61 state_(STATE_LOGIN_SCREEN), | |
| 62 util_(delegate_.get()), | |
| 63 component_extension_ime_manager_(new ComponentExtensionIMEManager()), | |
| 64 enable_extension_loading_(enable_extension_loading) { | |
| 65 if (base::SysInfo::IsRunningOnChromeOS()) | |
| 66 keyboard_.reset(ImeKeyboard::Create()); | |
| 67 else | |
| 68 keyboard_.reset(new FakeImeKeyboard()); | |
| 69 | 66 |
| 70 // Initializes the system IME list. | 67 active_input_method_ids = other.active_input_method_ids; |
| 71 scoped_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate( | 68 |
| 72 new ComponentExtensionIMEManagerImpl()); | 69 pending_input_method_id = other.pending_input_method_id; |
| 73 component_extension_ime_manager_->Initialize(comp_delegate.Pass()); | 70 |
| 74 util_.ResetInputMethods( | 71 enabled_extension_imes = other.enabled_extension_imes; |
| 75 component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor()); | 72 extra_input_methods = other.extra_input_methods; |
| 76 } | 73 } |
| 77 | 74 |
| 78 InputMethodManagerImpl::~InputMethodManagerImpl() { | 75 bool InputMethodManagerImpl::StateImpl::IsActive() const { |
| 79 if (candidate_window_controller_.get()) | 76 return manager_->state_.get() == this; |
| 80 candidate_window_controller_->RemoveObserver(this); | |
| 81 } | 77 } |
| 82 | 78 |
| 83 void InputMethodManagerImpl::AddObserver( | 79 std::string InputMethodManagerImpl::StateImpl::Dump() const { |
| 84 InputMethodManager::Observer* observer) { | 80 std::ostringstream os; |
| 85 observers_.AddObserver(observer); | 81 |
| 82 os << "################# " |
| 83 << (profile ? profile->GetProfileName() : std::string("NULL")) |
| 84 << " #################\n"; |
| 85 |
| 86 os << "previous_input_method: '" |
| 87 << previous_input_method.GetPreferredKeyboardLayout() << "'\n"; |
| 88 os << "current_input_method: '" |
| 89 << current_input_method.GetPreferredKeyboardLayout() << "'\n"; |
| 90 os << "active_input_method_ids (size=" << active_input_method_ids.size() |
| 91 << "):"; |
| 92 for (size_t i = 0; i < active_input_method_ids.size(); ++i) { |
| 93 os << " '" << active_input_method_ids[i] << "',"; |
| 94 } |
| 95 os << "\n"; |
| 96 os << "enabled_extension_imes (size=" << enabled_extension_imes.size() |
| 97 << "):"; |
| 98 for (size_t i = 0; i < enabled_extension_imes.size(); ++i) { |
| 99 os << " '" << enabled_extension_imes[i] << "'\n"; |
| 100 } |
| 101 os << "\n"; |
| 102 os << "extra_input_methods (size=" << extra_input_methods.size() << "):"; |
| 103 for (std::map<std::string, InputMethodDescriptor>::const_iterator it = |
| 104 extra_input_methods.begin(); |
| 105 it != extra_input_methods.end(); |
| 106 ++it) { |
| 107 os << " '" << it->first << "' => '" << it->second.id() << "',\n"; |
| 108 } |
| 109 os << "pending_input_method_id: '" << pending_input_method_id << "'\n"; |
| 110 |
| 111 return os.str(); |
| 86 } | 112 } |
| 87 | 113 |
| 88 void InputMethodManagerImpl::AddCandidateWindowObserver( | 114 scoped_refptr<InputMethodManager::State> |
| 89 InputMethodManager::CandidateWindowObserver* observer) { | 115 InputMethodManagerImpl::StateImpl::Clone() const { |
| 90 candidate_window_observers_.AddObserver(observer); | 116 scoped_refptr<StateImpl> new_state(new StateImpl(this->manager_, profile)); |
| 91 } | 117 new_state->InitFrom(*this); |
| 92 | 118 return scoped_refptr<InputMethodManager::State>(new_state.get()); |
| 93 void InputMethodManagerImpl::RemoveObserver( | |
| 94 InputMethodManager::Observer* observer) { | |
| 95 observers_.RemoveObserver(observer); | |
| 96 } | |
| 97 | |
| 98 void InputMethodManagerImpl::RemoveCandidateWindowObserver( | |
| 99 InputMethodManager::CandidateWindowObserver* observer) { | |
| 100 candidate_window_observers_.RemoveObserver(observer); | |
| 101 } | |
| 102 | |
| 103 InputMethodManager::State InputMethodManagerImpl::GetState() { | |
| 104 return state_; | |
| 105 } | |
| 106 | |
| 107 void InputMethodManagerImpl::SetState(State new_state) { | |
| 108 const State old_state = state_; | |
| 109 state_ = new_state; | |
| 110 switch (state_) { | |
| 111 case STATE_LOGIN_SCREEN: | |
| 112 break; | |
| 113 case STATE_BROWSER_SCREEN: | |
| 114 if (old_state == STATE_LOCK_SCREEN) | |
| 115 OnScreenUnlocked(); | |
| 116 break; | |
| 117 case STATE_LOCK_SCREEN: | |
| 118 OnScreenLocked(); | |
| 119 break; | |
| 120 case STATE_TERMINATING: { | |
| 121 if (candidate_window_controller_.get()) | |
| 122 candidate_window_controller_.reset(); | |
| 123 break; | |
| 124 } | |
| 125 } | |
| 126 } | 119 } |
| 127 | 120 |
| 128 scoped_ptr<InputMethodDescriptors> | 121 scoped_ptr<InputMethodDescriptors> |
| 129 InputMethodManagerImpl::GetSupportedInputMethods() const { | 122 InputMethodManagerImpl::StateImpl::GetActiveInputMethods() const { |
| 130 return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass(); | |
| 131 } | |
| 132 | |
| 133 scoped_ptr<InputMethodDescriptors> | |
| 134 InputMethodManagerImpl::GetActiveInputMethods() const { | |
| 135 scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors); | 123 scoped_ptr<InputMethodDescriptors> result(new InputMethodDescriptors); |
| 136 // Build the active input method descriptors from the active input | 124 // Build the active input method descriptors from the active input |
| 137 // methods cache |active_input_method_ids_|. | 125 // methods cache |active_input_method_ids|. |
| 138 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { | 126 for (size_t i = 0; i < active_input_method_ids.size(); ++i) { |
| 139 const std::string& input_method_id = active_input_method_ids_[i]; | 127 const std::string& input_method_id = active_input_method_ids[i]; |
| 140 const InputMethodDescriptor* descriptor = | 128 const InputMethodDescriptor* descriptor = |
| 141 util_.GetInputMethodDescriptorFromId(input_method_id); | 129 manager_->util_.GetInputMethodDescriptorFromId(input_method_id); |
| 142 if (descriptor) { | 130 if (descriptor) { |
| 143 result->push_back(*descriptor); | 131 result->push_back(*descriptor); |
| 144 } else { | 132 } else { |
| 145 std::map<std::string, InputMethodDescriptor>::const_iterator ix = | 133 std::map<std::string, InputMethodDescriptor>::const_iterator ix = |
| 146 extra_input_methods_.find(input_method_id); | 134 extra_input_methods.find(input_method_id); |
| 147 if (ix != extra_input_methods_.end()) | 135 if (ix != extra_input_methods.end()) |
| 148 result->push_back(ix->second); | 136 result->push_back(ix->second); |
| 149 else | 137 else |
| 150 DVLOG(1) << "Descriptor is not found for: " << input_method_id; | 138 DVLOG(1) << "Descriptor is not found for: " << input_method_id; |
| 151 } | 139 } |
| 152 } | 140 } |
| 153 if (result->empty()) { | 141 if (result->empty()) { |
| 154 // Initially |active_input_method_ids_| is empty. browser_tests might take | 142 // Initially |active_input_method_ids| is empty. browser_tests might take |
| 155 // this path. | 143 // this path. |
| 156 result->push_back( | 144 result->push_back( |
| 157 InputMethodUtil::GetFallbackInputMethodDescriptor()); | 145 InputMethodUtil::GetFallbackInputMethodDescriptor()); |
| 158 } | 146 } |
| 159 return result.Pass(); | 147 return result.Pass(); |
| 160 } | 148 } |
| 161 | 149 |
| 162 const std::vector<std::string>& | 150 const std::vector<std::string>& |
| 163 InputMethodManagerImpl::GetActiveInputMethodIds() const { | 151 InputMethodManagerImpl::StateImpl::GetActiveInputMethodIds() const { |
| 164 return active_input_method_ids_; | 152 return active_input_method_ids; |
| 165 } | 153 } |
| 166 | 154 |
| 167 size_t InputMethodManagerImpl::GetNumActiveInputMethods() const { | 155 size_t InputMethodManagerImpl::StateImpl::GetNumActiveInputMethods() const { |
| 168 return active_input_method_ids_.size(); | 156 return active_input_method_ids.size(); |
| 169 } | 157 } |
| 170 | 158 |
| 171 const InputMethodDescriptor* InputMethodManagerImpl::GetInputMethodFromId( | 159 const InputMethodDescriptor* |
| 160 InputMethodManagerImpl::StateImpl::GetInputMethodFromId( |
| 172 const std::string& input_method_id) const { | 161 const std::string& input_method_id) const { |
| 173 const InputMethodDescriptor* ime = util_.GetInputMethodDescriptorFromId( | 162 const InputMethodDescriptor* ime = |
| 174 input_method_id); | 163 manager_->util_.GetInputMethodDescriptorFromId(input_method_id); |
| 175 if (!ime) { | 164 if (!ime) { |
| 176 std::map<std::string, InputMethodDescriptor>::const_iterator ix = | 165 std::map<std::string, InputMethodDescriptor>::const_iterator ix = |
| 177 extra_input_methods_.find(input_method_id); | 166 extra_input_methods.find(input_method_id); |
| 178 if (ix != extra_input_methods_.end()) | 167 if (ix != extra_input_methods.end()) |
| 179 ime = &ix->second; | 168 ime = &ix->second; |
| 180 } | 169 } |
| 181 return ime; | 170 return ime; |
| 182 } | 171 } |
| 183 | 172 |
| 184 void InputMethodManagerImpl::EnableLoginLayouts( | 173 void InputMethodManagerImpl::StateImpl::EnableLoginLayouts( |
| 185 const std::string& language_code, | 174 const std::string& language_code, |
| 186 const std::vector<std::string>& initial_layouts) { | 175 const std::vector<std::string>& initial_layouts) { |
| 187 if (state_ == STATE_TERMINATING) | 176 if (manager_->ui_session_ == STATE_TERMINATING) |
| 188 return; | 177 return; |
| 189 | 178 |
| 190 // First, hardware keyboard layout should be shown. | 179 // First, hardware keyboard layout should be shown. |
| 191 std::vector<std::string> candidates = | 180 std::vector<std::string> candidates = |
| 192 util_.GetHardwareLoginInputMethodIds(); | 181 manager_->util_.GetHardwareLoginInputMethodIds(); |
| 193 | 182 |
| 194 // Seocnd, locale based input method should be shown. | 183 // Second, locale based input method should be shown. |
| 195 // Add input methods associated with the language. | 184 // Add input methods associated with the language. |
| 196 std::vector<std::string> layouts_from_locale; | 185 std::vector<std::string> layouts_from_locale; |
| 197 util_.GetInputMethodIdsFromLanguageCode(language_code, | 186 manager_->util_.GetInputMethodIdsFromLanguageCode( |
| 198 kKeyboardLayoutsOnly, | 187 language_code, kKeyboardLayoutsOnly, &layouts_from_locale); |
| 199 &layouts_from_locale); | |
| 200 candidates.insert(candidates.end(), layouts_from_locale.begin(), | 188 candidates.insert(candidates.end(), layouts_from_locale.begin(), |
| 201 layouts_from_locale.end()); | 189 layouts_from_locale.end()); |
| 202 | 190 |
| 203 std::vector<std::string> layouts; | 191 std::vector<std::string> layouts; |
| 204 // First, add the initial input method ID, if it's requested, to | 192 // First, add the initial input method ID, if it's requested, to |
| 205 // layouts, so it appears first on the list of active input | 193 // layouts, so it appears first on the list of active input |
| 206 // methods at the input language status menu. | 194 // methods at the input language status menu. |
| 207 for (size_t i = 0; i < initial_layouts.size(); ++i) { | 195 for (size_t i = 0; i < initial_layouts.size(); ++i) { |
| 208 if (util_.IsValidInputMethodId(initial_layouts[i])) { | 196 if (manager_->util_.IsValidInputMethodId(initial_layouts[i])) { |
| 209 if (IsLoginKeyboard(initial_layouts[i])) { | 197 if (manager_->IsLoginKeyboard(initial_layouts[i])) { |
| 210 layouts.push_back(initial_layouts[i]); | 198 layouts.push_back(initial_layouts[i]); |
| 211 } else { | 199 } else { |
| 212 DVLOG(1) | 200 DVLOG(1) |
| 213 << "EnableLoginLayouts: ignoring non-login initial keyboard layout:" | 201 << "EnableLoginLayouts: ignoring non-login initial keyboard layout:" |
| 214 << initial_layouts[i]; | 202 << initial_layouts[i]; |
| 215 } | 203 } |
| 216 } else if (!initial_layouts[i].empty()) { | 204 } else if (!initial_layouts[i].empty()) { |
| 217 DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: " | 205 DVLOG(1) << "EnableLoginLayouts: ignoring non-keyboard or invalid ID: " |
| 218 << initial_layouts[i]; | 206 << initial_layouts[i]; |
| 219 } | 207 } |
| 220 } | 208 } |
| 221 | 209 |
| 222 // Add candidates to layouts, while skipping duplicates. | 210 // Add candidates to layouts, while skipping duplicates. |
| 223 for (size_t i = 0; i < candidates.size(); ++i) { | 211 for (size_t i = 0; i < candidates.size(); ++i) { |
| 224 const std::string& candidate = candidates[i]; | 212 const std::string& candidate = candidates[i]; |
| 225 // Not efficient, but should be fine, as the two vectors are very | 213 // Not efficient, but should be fine, as the two vectors are very |
| 226 // short (2-5 items). | 214 // short (2-5 items). |
| 227 if (!Contains(layouts, candidate) && IsLoginKeyboard(candidate)) | 215 if (!Contains(layouts, candidate) && manager_->IsLoginKeyboard(candidate)) |
| 228 layouts.push_back(candidate); | 216 layouts.push_back(candidate); |
| 229 } | 217 } |
| 230 | 218 |
| 231 MigrateInputMethods(&layouts); | 219 manager_->MigrateInputMethods(&layouts); |
| 232 active_input_method_ids_.swap(layouts); | 220 active_input_method_ids.swap(layouts); |
| 233 | 221 |
| 234 // Initialize candidate window controller and widgets such as | 222 if (IsActive()) { |
| 235 // candidate window, infolist and mode indicator. Note, mode | 223 // Initialize candidate window controller and widgets such as |
| 236 // indicator is used by only keyboard layout input methods. | 224 // candidate window, infolist and mode indicator. Note, mode |
| 237 if (active_input_method_ids_.size() > 1) | 225 // indicator is used by only keyboard layout input methods. |
| 238 MaybeInitializeCandidateWindowController(); | 226 if (active_input_method_ids.size() > 1) |
| 227 manager_->MaybeInitializeCandidateWindowController(); |
| 239 | 228 |
| 240 // you can pass empty |initial_layout|. | 229 // you can pass empty |initial_layout|. |
| 241 ChangeInputMethod(initial_layouts.empty() ? "" : | 230 ChangeInputMethod(initial_layouts.empty() |
| 242 extension_ime_util::GetInputMethodIDByEngineID(initial_layouts[0])); | 231 ? std::string() |
| 232 : extension_ime_util::GetInputMethodIDByEngineID( |
| 233 initial_layouts[0]), |
| 234 false); |
| 235 } |
| 236 } |
| 237 |
| 238 void InputMethodManagerImpl::StateImpl::EnableLockScreenLayouts() { |
| 239 std::set<std::string> added_ids; |
| 240 |
| 241 const std::vector<std::string>& hardware_keyboard_ids = |
| 242 manager_->util_.GetHardwareLoginInputMethodIds(); |
| 243 |
| 244 std::vector<std::string> new_active_input_method_ids; |
| 245 for (size_t i = 0; i < active_input_method_ids.size(); ++i) { |
| 246 const std::string& input_method_id = active_input_method_ids[i]; |
| 247 // Skip if it's not a keyboard layout. Drop input methods including |
| 248 // extension ones. |
| 249 if (!manager_->IsLoginKeyboard(input_method_id) || |
| 250 added_ids.count(input_method_id)) { |
| 251 continue; |
| 252 } |
| 253 new_active_input_method_ids.push_back(input_method_id); |
| 254 added_ids.insert(input_method_id); |
| 255 } |
| 256 |
| 257 // We'll add the hardware keyboard if it's not included in |
| 258 // |active_input_method_ids| so that the user can always use the hardware |
| 259 // keyboard on the screen locker. |
| 260 for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) { |
| 261 if (added_ids.count(hardware_keyboard_ids[i])) |
| 262 continue; |
| 263 new_active_input_method_ids.push_back(hardware_keyboard_ids[i]); |
| 264 added_ids.insert(hardware_keyboard_ids[i]); |
| 265 } |
| 266 |
| 267 active_input_method_ids.swap(new_active_input_method_ids); |
| 268 |
| 269 // Re-check current_input_method. |
| 270 ChangeInputMethod(current_input_method.id(), false); |
| 243 } | 271 } |
| 244 | 272 |
| 245 // Adds new input method to given list. | 273 // Adds new input method to given list. |
| 246 bool InputMethodManagerImpl::EnableInputMethodImpl( | 274 bool InputMethodManagerImpl::StateImpl::EnableInputMethodImpl( |
| 247 const std::string& input_method_id, | 275 const std::string& input_method_id, |
| 248 std::vector<std::string>* new_active_input_method_ids) const { | 276 std::vector<std::string>* new_active_input_method_ids) const { |
| 249 DCHECK(new_active_input_method_ids); | 277 DCHECK(new_active_input_method_ids); |
| 250 if (!util_.IsValidInputMethodId(input_method_id)) { | 278 if (!manager_->util_.IsValidInputMethodId(input_method_id)) { |
| 251 DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id; | 279 DVLOG(1) << "EnableInputMethod: Invalid ID: " << input_method_id; |
| 252 return false; | 280 return false; |
| 253 } | 281 } |
| 254 | 282 |
| 255 if (!Contains(*new_active_input_method_ids, input_method_id)) | 283 if (!Contains(*new_active_input_method_ids, input_method_id)) |
| 256 new_active_input_method_ids->push_back(input_method_id); | 284 new_active_input_method_ids->push_back(input_method_id); |
| 257 | 285 |
| 258 return true; | 286 return true; |
| 259 } | 287 } |
| 260 | 288 |
| 261 // Starts or stops the system input method framework as needed. | 289 bool InputMethodManagerImpl::StateImpl::EnableInputMethod( |
| 262 void InputMethodManagerImpl::ReconfigureIMFramework() { | |
| 263 LoadNecessaryComponentExtensions(); | |
| 264 | |
| 265 // Initialize candidate window controller and widgets such as | |
| 266 // candidate window, infolist and mode indicator. Note, mode | |
| 267 // indicator is used by only keyboard layout input methods. | |
| 268 MaybeInitializeCandidateWindowController(); | |
| 269 } | |
| 270 | |
| 271 bool InputMethodManagerImpl::EnableInputMethod( | |
| 272 const std::string& input_method_id) { | 290 const std::string& input_method_id) { |
| 273 if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids_)) | 291 if (!EnableInputMethodImpl(input_method_id, &active_input_method_ids)) |
| 274 return false; | 292 return false; |
| 275 | 293 |
| 276 ReconfigureIMFramework(); | 294 manager_->ReconfigureIMFramework(this); |
| 277 return true; | 295 return true; |
| 278 } | 296 } |
| 279 | 297 |
| 280 bool InputMethodManagerImpl::ReplaceEnabledInputMethods( | 298 bool InputMethodManagerImpl::StateImpl::ReplaceEnabledInputMethods( |
| 281 const std::vector<std::string>& new_active_input_method_ids) { | 299 const std::vector<std::string>& new_active_input_method_ids) { |
| 282 if (state_ == STATE_TERMINATING) | 300 if (manager_->ui_session_ == STATE_TERMINATING) |
| 283 return false; | 301 return false; |
| 284 | 302 |
| 285 // Filter unknown or obsolete IDs. | 303 // Filter unknown or obsolete IDs. |
| 286 std::vector<std::string> new_active_input_method_ids_filtered; | 304 std::vector<std::string> new_active_input_method_ids_filtered; |
| 287 | 305 |
| 288 for (size_t i = 0; i < new_active_input_method_ids.size(); ++i) | 306 for (size_t i = 0; i < new_active_input_method_ids.size(); ++i) |
| 289 EnableInputMethodImpl(new_active_input_method_ids[i], | 307 EnableInputMethodImpl(new_active_input_method_ids[i], |
| 290 &new_active_input_method_ids_filtered); | 308 &new_active_input_method_ids_filtered); |
| 291 | 309 |
| 292 if (new_active_input_method_ids_filtered.empty()) { | 310 if (new_active_input_method_ids_filtered.empty()) { |
| 293 DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID"; | 311 DVLOG(1) << "ReplaceEnabledInputMethods: No valid input method ID"; |
| 294 return false; | 312 return false; |
| 295 } | 313 } |
| 296 | 314 |
| 297 // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to | 315 // Copy extension IDs to |new_active_input_method_ids_filtered|. We have to |
| 298 // keep relative order of the extension input method IDs. | 316 // keep relative order of the extension input method IDs. |
| 299 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { | 317 for (size_t i = 0; i < active_input_method_ids.size(); ++i) { |
| 300 const std::string& input_method_id = active_input_method_ids_[i]; | 318 const std::string& input_method_id = active_input_method_ids[i]; |
| 301 if (extension_ime_util::IsExtensionIME(input_method_id)) | 319 if (extension_ime_util::IsExtensionIME(input_method_id)) |
| 302 new_active_input_method_ids_filtered.push_back(input_method_id); | 320 new_active_input_method_ids_filtered.push_back(input_method_id); |
| 303 } | 321 } |
| 304 active_input_method_ids_.swap(new_active_input_method_ids_filtered); | 322 active_input_method_ids.swap(new_active_input_method_ids_filtered); |
| 305 MigrateInputMethods(&active_input_method_ids_); | 323 manager_->MigrateInputMethods(&active_input_method_ids); |
| 306 | 324 |
| 307 ReconfigureIMFramework(); | 325 manager_->ReconfigureIMFramework(this); |
| 308 | 326 |
| 309 // If |current_input_method| is no longer in |active_input_method_ids_|, | 327 // If |current_input_method| is no longer in |active_input_method_ids|, |
| 310 // ChangeInputMethod() picks the first one in |active_input_method_ids_|. | 328 // ChangeInputMethod() picks the first one in |active_input_method_ids|. |
| 311 ChangeInputMethod(current_input_method_.id()); | 329 ChangeInputMethod(current_input_method.id(), false); |
| 312 return true; | 330 return true; |
| 313 } | 331 } |
| 314 | 332 |
| 315 void InputMethodManagerImpl::ChangeInputMethod( | 333 void InputMethodManagerImpl::StateImpl::ChangeInputMethod( |
| 316 const std::string& input_method_id) { | 334 const std::string& input_method_id, |
| 317 ChangeInputMethodInternal(input_method_id, false); | 335 bool show_message) { |
| 336 if (manager_->ui_session_ == STATE_TERMINATING) |
| 337 return; |
| 338 |
| 339 bool notify_menu = false; |
| 340 // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes |
| 341 // happens after activating the 3rd party IME. |
| 342 // So here to record the 3rd party IME to be activated, and activate it |
| 343 // when SetEnabledExtensionImes happens later. |
| 344 if (MethodAwaitsExtensionLoad(input_method_id)) |
| 345 pending_input_method_id = input_method_id; |
| 346 |
| 347 // Always lookup input method, even if it is the same as |
| 348 // |current_input_method| because If it is no longer in |
| 349 // |active_input_method_ids|, pick the first one in |
| 350 // |active_input_method_ids|. |
| 351 const InputMethodDescriptor* descriptor = |
| 352 manager_->LookupInputMethod(input_method_id, this); |
| 353 if (descriptor->id() != current_input_method.id()) { |
| 354 previous_input_method = current_input_method; |
| 355 current_input_method = *descriptor; |
| 356 notify_menu = true; |
| 357 } |
| 358 |
| 359 // Always change input method even if it is the same. |
| 360 // TODO(komatsu): Revisit if this is neccessary. |
| 361 if (IsActive()) |
| 362 manager_->ChangeInputMethodInternal(*descriptor, show_message, notify_menu); |
| 318 } | 363 } |
| 319 | 364 |
| 320 bool InputMethodManagerImpl::ChangeInputMethodInternal( | 365 bool InputMethodManagerImpl::StateImpl::MethodAwaitsExtensionLoad( |
| 321 const std::string& input_method_id, | 366 const std::string& input_method_id) const { |
| 322 bool show_message) { | 367 // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes |
| 323 if (state_ == STATE_TERMINATING) | 368 // happens after activating the 3rd party IME. |
| 324 return false; | 369 // So here to record the 3rd party IME to be activated, and activate it |
| 325 | 370 // when SetEnabledExtensionImes happens later. |
| 326 std::string input_method_id_to_switch = input_method_id; | 371 return !InputMethodIsActivated(input_method_id) && |
| 327 | 372 extension_ime_util::IsExtensionIME(input_method_id); |
| 328 // Sanity check. | |
| 329 if (!InputMethodIsActivated(input_method_id)) { | |
| 330 // For 3rd party IME, when the user just logged in, SetEnabledExtensionImes | |
| 331 // happens after activating the 3rd party IME. | |
| 332 // So here to record the 3rd party IME to be activated, and activate it | |
| 333 // when SetEnabledExtensionImes happens later. | |
| 334 if (extension_ime_util::IsExtensionIME(input_method_id)) | |
| 335 pending_input_method_id_ = input_method_id; | |
| 336 | |
| 337 scoped_ptr<InputMethodDescriptors> input_methods(GetActiveInputMethods()); | |
| 338 DCHECK(!input_methods->empty()); | |
| 339 input_method_id_to_switch = input_methods->at(0).id(); | |
| 340 if (!input_method_id.empty()) { | |
| 341 DVLOG(1) << "Can't change the current input method to " | |
| 342 << input_method_id << " since the engine is not enabled. " | |
| 343 << "Switch to " << input_method_id_to_switch << " instead."; | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 // Hide candidate window and info list. | |
| 348 if (candidate_window_controller_.get()) | |
| 349 candidate_window_controller_->Hide(); | |
| 350 | |
| 351 // TODO(komatsu): Check if it is necessary to perform the above routine | |
| 352 // when the current input method is equal to |input_method_id_to_swich|. | |
| 353 if (current_input_method_.id() != input_method_id_to_switch) { | |
| 354 // Clear property list. Property list would be updated by | |
| 355 // extension IMEs via InputMethodEngine::(Set|Update)MenuItems. | |
| 356 // If the current input method is a keyboard layout, empty | |
| 357 // properties are sufficient. | |
| 358 const ash::ime::InputMethodMenuItemList empty_menu_item_list; | |
| 359 ash::ime::InputMethodMenuManager* input_method_menu_manager = | |
| 360 ash::ime::InputMethodMenuManager::GetInstance(); | |
| 361 input_method_menu_manager->SetCurrentInputMethodMenuItemList( | |
| 362 empty_menu_item_list); | |
| 363 | |
| 364 const InputMethodDescriptor* descriptor = NULL; | |
| 365 if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) { | |
| 366 DCHECK(extra_input_methods_.find(input_method_id_to_switch) != | |
| 367 extra_input_methods_.end()); | |
| 368 descriptor = &(extra_input_methods_[input_method_id_to_switch]); | |
| 369 } else { | |
| 370 descriptor = | |
| 371 util_.GetInputMethodDescriptorFromId(input_method_id_to_switch); | |
| 372 if (!descriptor) | |
| 373 LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch; | |
| 374 } | |
| 375 DCHECK(descriptor); | |
| 376 | |
| 377 previous_input_method_ = current_input_method_; | |
| 378 current_input_method_ = *descriptor; | |
| 379 } | |
| 380 | |
| 381 // Disable the current engine handler. | |
| 382 IMEEngineHandlerInterface* engine = | |
| 383 IMEBridge::Get()->GetCurrentEngineHandler(); | |
| 384 if (engine) | |
| 385 engine->Disable(); | |
| 386 | |
| 387 // Configure the next engine handler. | |
| 388 // This must be after |current_input_method_| has been set to new input | |
| 389 // method, because engine's Enable() method needs to access it. | |
| 390 const std::string& extension_id = | |
| 391 extension_ime_util::GetExtensionIDFromInputMethodID( | |
| 392 input_method_id_to_switch); | |
| 393 const std::string& component_id = | |
| 394 extension_ime_util::GetComponentIDByInputMethodID( | |
| 395 input_method_id_to_switch); | |
| 396 engine = engine_map_[extension_id]; | |
| 397 IMEBridge::Get()->SetCurrentEngineHandler(engine); | |
| 398 if (engine) | |
| 399 engine->Enable(component_id); | |
| 400 | |
| 401 // Change the keyboard layout to a preferred layout for the input method. | |
| 402 if (!keyboard_->SetCurrentKeyboardLayoutByName( | |
| 403 current_input_method_.GetPreferredKeyboardLayout())) { | |
| 404 LOG(ERROR) << "Failed to change keyboard layout to " | |
| 405 << current_input_method_.GetPreferredKeyboardLayout(); | |
| 406 } | |
| 407 | |
| 408 // Update input method indicators (e.g. "US", "DV") in Chrome windows. | |
| 409 FOR_EACH_OBSERVER(InputMethodManager::Observer, | |
| 410 observers_, | |
| 411 InputMethodChanged(this, show_message)); | |
| 412 return true; | |
| 413 } | 373 } |
| 414 | 374 |
| 415 void InputMethodManagerImpl::LoadNecessaryComponentExtensions() { | 375 void InputMethodManagerImpl::StateImpl::AddInputMethodExtension( |
| 416 // Load component extensions but also update |active_input_method_ids_| as | |
| 417 // some component extension IMEs may have been removed from the Chrome OS | |
| 418 // image. If specified component extension IME no longer exists, falling back | |
| 419 // to an existing IME. | |
| 420 std::vector<std::string> unfiltered_input_method_ids; | |
| 421 unfiltered_input_method_ids.swap(active_input_method_ids_); | |
| 422 for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) { | |
| 423 if (!extension_ime_util::IsComponentExtensionIME( | |
| 424 unfiltered_input_method_ids[i])) { | |
| 425 // Legacy IMEs or xkb layouts are alwayes active. | |
| 426 active_input_method_ids_.push_back(unfiltered_input_method_ids[i]); | |
| 427 } else if (component_extension_ime_manager_->IsWhitelisted( | |
| 428 unfiltered_input_method_ids[i])) { | |
| 429 if (enable_extension_loading_) | |
| 430 component_extension_ime_manager_->LoadComponentExtensionIME( | |
| 431 unfiltered_input_method_ids[i]); | |
| 432 active_input_method_ids_.push_back(unfiltered_input_method_ids[i]); | |
| 433 } | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 void InputMethodManagerImpl::ActivateInputMethodMenuItem( | |
| 438 const std::string& key) { | |
| 439 DCHECK(!key.empty()); | |
| 440 | |
| 441 if (ash::ime::InputMethodMenuManager::GetInstance()-> | |
| 442 HasInputMethodMenuItemForKey(key)) { | |
| 443 IMEEngineHandlerInterface* engine = | |
| 444 IMEBridge::Get()->GetCurrentEngineHandler(); | |
| 445 if (engine) | |
| 446 engine->PropertyActivate(key); | |
| 447 return; | |
| 448 } | |
| 449 | |
| 450 DVLOG(1) << "ActivateInputMethodMenuItem: unknown key: " << key; | |
| 451 } | |
| 452 | |
| 453 void InputMethodManagerImpl::AddInputMethodExtension( | |
| 454 const std::string& extension_id, | 376 const std::string& extension_id, |
| 455 const InputMethodDescriptors& descriptors, | 377 const InputMethodDescriptors& descriptors, |
| 456 InputMethodEngineInterface* engine) { | 378 InputMethodEngineInterface* engine) { |
| 457 if (state_ == STATE_TERMINATING) | 379 if (manager_->ui_session_ == STATE_TERMINATING) |
| 458 return; | 380 return; |
| 459 | 381 |
| 460 DCHECK(engine); | 382 DCHECK(engine); |
| 461 | 383 |
| 462 engine_map_[extension_id] = engine; | 384 manager_->engine_map_[extension_id] = engine; |
| 463 | |
| 464 if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID( | |
| 465 current_input_method_.id())) { | |
| 466 IMEBridge::Get()->SetCurrentEngineHandler(engine); | |
| 467 engine->Enable(extension_ime_util::GetComponentIDByInputMethodID( | |
| 468 current_input_method_.id())); | |
| 469 } | |
| 470 | 385 |
| 471 bool contain = false; | 386 bool contain = false; |
| 472 for (size_t i = 0; i < descriptors.size(); i++) { | 387 for (size_t i = 0; i < descriptors.size(); i++) { |
| 473 const InputMethodDescriptor& descriptor = descriptors[i]; | 388 const InputMethodDescriptor& descriptor = descriptors[i]; |
| 474 const std::string& id = descriptor.id(); | 389 const std::string& id = descriptor.id(); |
| 475 extra_input_methods_[id] = descriptor; | 390 extra_input_methods[id] = descriptor; |
| 476 if (Contains(enabled_extension_imes_, id)) { | 391 if (Contains(enabled_extension_imes, id)) { |
| 477 if (!Contains(active_input_method_ids_, id)) { | 392 if (!Contains(active_input_method_ids, id)) { |
| 478 active_input_method_ids_.push_back(id); | 393 active_input_method_ids.push_back(id); |
| 479 } else { | 394 } else { |
| 480 DVLOG(1) << "AddInputMethodExtension: already added: " << id << ", " | 395 DVLOG(1) << "AddInputMethodExtension: already added: " << id << ", " |
| 481 << descriptor.name(); | 396 << descriptor.name(); |
| 482 } | 397 } |
| 483 contain = true; | 398 contain = true; |
| 484 } | 399 } |
| 485 } | 400 } |
| 486 | 401 |
| 487 // Ensure that the input method daemon is running. | 402 if (IsActive()) { |
| 488 if (contain) | 403 if (extension_id == extension_ime_util::GetExtensionIDFromInputMethodID( |
| 489 MaybeInitializeCandidateWindowController(); | 404 current_input_method.id())) { |
| 405 IMEBridge::Get()->SetCurrentEngineHandler(engine); |
| 406 engine->Enable(extension_ime_util::GetComponentIDByInputMethodID( |
| 407 current_input_method.id())); |
| 408 } |
| 409 |
| 410 // Ensure that the input method daemon is running. |
| 411 if (contain) |
| 412 manager_->MaybeInitializeCandidateWindowController(); |
| 413 } |
| 490 } | 414 } |
| 491 | 415 |
| 492 void InputMethodManagerImpl::RemoveInputMethodExtension( | 416 void InputMethodManagerImpl::StateImpl::RemoveInputMethodExtension( |
| 493 const std::string& extension_id) { | 417 const std::string& extension_id) { |
| 494 // Remove the active input methods with |extension_id|. | 418 // Remove the active input methods with |extension_id|. |
| 495 std::vector<std::string> new_active_input_method_ids; | 419 std::vector<std::string> new_active_input_method_ids; |
| 496 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { | 420 for (size_t i = 0; i < active_input_method_ids.size(); ++i) { |
| 497 if (extension_id != extension_ime_util::GetExtensionIDFromInputMethodID( | 421 if (extension_id != extension_ime_util::GetExtensionIDFromInputMethodID( |
| 498 active_input_method_ids_[i])) | 422 active_input_method_ids[i])) |
| 499 new_active_input_method_ids.push_back(active_input_method_ids_[i]); | 423 new_active_input_method_ids.push_back(active_input_method_ids[i]); |
| 500 } | 424 } |
| 501 active_input_method_ids_.swap(new_active_input_method_ids); | 425 active_input_method_ids.swap(new_active_input_method_ids); |
| 502 | 426 |
| 503 // Remove the extra input methods with |extension_id|. | 427 // Remove the extra input methods with |extension_id|. |
| 504 std::map<std::string, InputMethodDescriptor> new_extra_input_methods; | 428 std::map<std::string, InputMethodDescriptor> new_extra_input_methods; |
| 505 for (std::map<std::string, InputMethodDescriptor>::iterator i = | 429 for (std::map<std::string, InputMethodDescriptor>::iterator i = |
| 506 extra_input_methods_.begin(); | 430 extra_input_methods.begin(); |
| 507 i != extra_input_methods_.end(); | 431 i != extra_input_methods.end(); |
| 508 ++i) { | 432 ++i) { |
| 509 if (extension_id != | 433 if (extension_id != |
| 510 extension_ime_util::GetExtensionIDFromInputMethodID(i->first)) | 434 extension_ime_util::GetExtensionIDFromInputMethodID(i->first)) |
| 511 new_extra_input_methods[i->first] = i->second; | 435 new_extra_input_methods[i->first] = i->second; |
| 512 } | 436 } |
| 513 extra_input_methods_.swap(new_extra_input_methods); | 437 extra_input_methods.swap(new_extra_input_methods); |
| 514 | 438 |
| 515 if (IMEBridge::Get()->GetCurrentEngineHandler() == engine_map_[extension_id]) | 439 if (IsActive()) { |
| 516 IMEBridge::Get()->SetCurrentEngineHandler(NULL); | 440 if (IMEBridge::Get()->GetCurrentEngineHandler() == |
| 517 engine_map_.erase(extension_id); | 441 manager_->engine_map_[extension_id]) { |
| 442 IMEBridge::Get()->SetCurrentEngineHandler(NULL); |
| 443 } |
| 444 manager_->engine_map_.erase(extension_id); |
| 445 } |
| 518 | 446 |
| 519 // No need to switch input method when terminating. | 447 // If |current_input_method| is no longer in |active_input_method_ids|, |
| 520 if (state_ != STATE_TERMINATING) { | 448 // switch to the first one in |active_input_method_ids|. |
| 521 // If |current_input_method| is no longer in |active_input_method_ids_|, | 449 ChangeInputMethod(current_input_method.id(), false); |
| 522 // switch to the first one in |active_input_method_ids_|. | |
| 523 ChangeInputMethod(current_input_method_.id()); | |
| 524 } | |
| 525 } | 450 } |
| 526 | 451 |
| 527 void InputMethodManagerImpl::GetInputMethodExtensions( | 452 void InputMethodManagerImpl::StateImpl::GetInputMethodExtensions( |
| 528 InputMethodDescriptors* result) { | 453 InputMethodDescriptors* result) { |
| 529 // Build the extension input method descriptors from the extra input | 454 // Build the extension input method descriptors from the extra input |
| 530 // methods cache |extra_input_methods_|. | 455 // methods cache |extra_input_methods|. |
| 531 std::map<std::string, InputMethodDescriptor>::iterator iter; | 456 std::map<std::string, InputMethodDescriptor>::iterator iter; |
| 532 for (iter = extra_input_methods_.begin(); iter != extra_input_methods_.end(); | 457 for (iter = extra_input_methods.begin(); iter != extra_input_methods.end(); |
| 533 ++iter) { | 458 ++iter) { |
| 534 if (extension_ime_util::IsExtensionIME(iter->first)) | 459 if (extension_ime_util::IsExtensionIME(iter->first)) |
| 535 result->push_back(iter->second); | 460 result->push_back(iter->second); |
| 536 } | 461 } |
| 537 } | 462 } |
| 538 | 463 |
| 539 void InputMethodManagerImpl::SetEnabledExtensionImes( | 464 void InputMethodManagerImpl::StateImpl::SetEnabledExtensionImes( |
| 540 std::vector<std::string>* ids) { | 465 std::vector<std::string>* ids) { |
| 541 enabled_extension_imes_.clear(); | 466 enabled_extension_imes.clear(); |
| 542 enabled_extension_imes_.insert(enabled_extension_imes_.end(), | 467 enabled_extension_imes.insert( |
| 543 ids->begin(), | 468 enabled_extension_imes.end(), ids->begin(), ids->end()); |
| 544 ids->end()); | |
| 545 | |
| 546 bool active_imes_changed = false; | 469 bool active_imes_changed = false; |
| 547 bool switch_to_pending = false; | 470 bool switch_to_pending = false; |
| 548 | 471 |
| 549 for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter = | 472 for (std::map<std::string, InputMethodDescriptor>::iterator extra_iter = |
| 550 extra_input_methods_.begin(); extra_iter != extra_input_methods_.end(); | 473 extra_input_methods.begin(); |
| 474 extra_iter != extra_input_methods.end(); |
| 551 ++extra_iter) { | 475 ++extra_iter) { |
| 552 if (extension_ime_util::IsComponentExtensionIME( | 476 if (extension_ime_util::IsComponentExtensionIME(extra_iter->first)) |
| 553 extra_iter->first)) | |
| 554 continue; // Do not filter component extension. | 477 continue; // Do not filter component extension. |
| 555 | 478 |
| 556 if (pending_input_method_id_ == extra_iter->first) | 479 if (pending_input_method_id == extra_iter->first) |
| 557 switch_to_pending = true; | 480 switch_to_pending = true; |
| 558 | 481 |
| 559 std::vector<std::string>::iterator active_iter = std::find( | 482 std::vector<std::string>::iterator active_iter = |
| 560 active_input_method_ids_.begin(), active_input_method_ids_.end(), | 483 std::find(active_input_method_ids.begin(), |
| 561 extra_iter->first); | 484 active_input_method_ids.end(), |
| 485 extra_iter->first); |
| 562 | 486 |
| 563 bool active = active_iter != active_input_method_ids_.end(); | 487 bool active = active_iter != active_input_method_ids.end(); |
| 564 bool enabled = Contains(enabled_extension_imes_, extra_iter->first); | 488 bool enabled = Contains(enabled_extension_imes, extra_iter->first); |
| 565 | 489 |
| 566 if (active && !enabled) | 490 if (active && !enabled) |
| 567 active_input_method_ids_.erase(active_iter); | 491 active_input_method_ids.erase(active_iter); |
| 568 | 492 |
| 569 if (!active && enabled) | 493 if (!active && enabled) |
| 570 active_input_method_ids_.push_back(extra_iter->first); | 494 active_input_method_ids.push_back(extra_iter->first); |
| 571 | 495 |
| 572 if (active == !enabled) | 496 if (active == !enabled) |
| 573 active_imes_changed = true; | 497 active_imes_changed = true; |
| 574 } | 498 } |
| 575 | 499 |
| 576 if (active_imes_changed) { | 500 if (IsActive() && active_imes_changed) { |
| 577 MaybeInitializeCandidateWindowController(); | 501 manager_->MaybeInitializeCandidateWindowController(); |
| 578 | 502 |
| 579 if (switch_to_pending) { | 503 if (switch_to_pending) { |
| 580 ChangeInputMethod(pending_input_method_id_); | 504 ChangeInputMethod(pending_input_method_id, false); |
| 581 pending_input_method_id_.clear(); | 505 pending_input_method_id.clear(); |
| 582 } else { | 506 } else { |
| 583 // If |current_input_method| is no longer in |active_input_method_ids_|, | 507 // If |current_input_method| is no longer in |active_input_method_ids_|, |
| 584 // switch to the first one in |active_input_method_ids_|. | 508 // switch to the first one in |active_input_method_ids_|. |
| 585 ChangeInputMethod(current_input_method_.id()); | 509 ChangeInputMethod(current_input_method.id(), false); |
| 586 } | 510 } |
| 587 } | 511 } |
| 588 } | 512 } |
| 589 | 513 |
| 590 void InputMethodManagerImpl::SetInputMethodLoginDefaultFromVPD( | 514 void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefaultFromVPD( |
| 591 const std::string& locale, const std::string& oem_layout) { | 515 const std::string& locale, |
| 516 const std::string& oem_layout) { |
| 592 std::string layout; | 517 std::string layout; |
| 593 if (!oem_layout.empty()) { | 518 if (!oem_layout.empty()) { |
| 594 // If the OEM layout information is provided, use it. | 519 // If the OEM layout information is provided, use it. |
| 595 layout = oem_layout; | 520 layout = oem_layout; |
| 596 } else { | 521 } else { |
| 597 // Otherwise, determine the hardware keyboard from the locale. | 522 // Otherwise, determine the hardware keyboard from the locale. |
| 598 std::vector<std::string> input_method_ids; | 523 std::vector<std::string> input_method_ids; |
| 599 if (util_.GetInputMethodIdsFromLanguageCode( | 524 if (manager_->util_.GetInputMethodIdsFromLanguageCode( |
| 600 locale, | 525 locale, |
| 601 chromeos::input_method::kKeyboardLayoutsOnly, | 526 chromeos::input_method::kKeyboardLayoutsOnly, |
| 602 &input_method_ids)) { | 527 &input_method_ids)) { |
| 603 // The output list |input_method_ids| is sorted by popularity, hence | 528 // The output list |input_method_ids| is sorted by popularity, hence |
| 604 // input_method_ids[0] now contains the most popular keyboard layout | 529 // input_method_ids[0] now contains the most popular keyboard layout |
| 605 // for the given locale. | 530 // for the given locale. |
| 606 DCHECK_GE(input_method_ids.size(), 1U); | 531 DCHECK_GE(input_method_ids.size(), 1U); |
| 607 layout = input_method_ids[0]; | 532 layout = input_method_ids[0]; |
| 608 } | 533 } |
| 609 } | 534 } |
| 610 | 535 |
| 611 if (layout.empty()) | 536 if (layout.empty()) |
| 612 return; | 537 return; |
| 613 | 538 |
| 614 std::vector<std::string> layouts; | 539 std::vector<std::string> layouts; |
| 615 base::SplitString(layout, ',', &layouts); | 540 base::SplitString(layout, ',', &layouts); |
| 616 MigrateInputMethods(&layouts); | 541 manager_->MigrateInputMethods(&layouts); |
| 617 | 542 |
| 618 PrefService* prefs = g_browser_process->local_state(); | 543 PrefService* prefs = g_browser_process->local_state(); |
| 619 prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ",")); | 544 prefs->SetString(prefs::kHardwareKeyboardLayout, JoinString(layouts, ",")); |
| 620 | 545 |
| 621 // This asks the file thread to save the prefs (i.e. doesn't block). | 546 // This asks the file thread to save the prefs (i.e. doesn't block). |
| 622 // The latest values of Local State reside in memory so we can safely | 547 // The latest values of Local State reside in memory so we can safely |
| 623 // get the value of kHardwareKeyboardLayout even if the data is not | 548 // get the value of kHardwareKeyboardLayout even if the data is not |
| 624 // yet saved to disk. | 549 // yet saved to disk. |
| 625 prefs->CommitPendingWrite(); | 550 prefs->CommitPendingWrite(); |
| 626 | 551 |
| 627 util_.UpdateHardwareLayoutCache(); | 552 manager_->util_.UpdateHardwareLayoutCache(); |
| 628 | 553 |
| 629 EnableLoginLayouts(locale, layouts); | 554 EnableLoginLayouts(locale, layouts); |
| 630 LoadNecessaryComponentExtensions(); | 555 manager_->LoadNecessaryComponentExtensions(this); |
| 631 } | 556 } |
| 632 | 557 |
| 633 void InputMethodManagerImpl::SetInputMethodLoginDefault() { | 558 void InputMethodManagerImpl::StateImpl::SetInputMethodLoginDefault() { |
| 634 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty | 559 // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty |
| 635 // and US dvorak keyboard layouts. | 560 // and US dvorak keyboard layouts. |
| 636 if (g_browser_process && g_browser_process->local_state()) { | 561 if (g_browser_process && g_browser_process->local_state()) { |
| 637 const std::string locale = g_browser_process->GetApplicationLocale(); | 562 const std::string locale = g_browser_process->GetApplicationLocale(); |
| 638 // If the preferred keyboard for the login screen has been saved, use it. | 563 // If the preferred keyboard for the login screen has been saved, use it. |
| 639 PrefService* prefs = g_browser_process->local_state(); | 564 PrefService* prefs = g_browser_process->local_state(); |
| 640 std::string initial_input_method_id = | 565 std::string initial_input_method_id = |
| 641 prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout); | 566 prefs->GetString(chromeos::language_prefs::kPreferredKeyboardLayout); |
| 642 std::vector<std::string> input_methods_to_be_enabled; | 567 std::vector<std::string> input_methods_to_be_enabled; |
| 643 if (initial_input_method_id.empty()) { | 568 if (initial_input_method_id.empty()) { |
| 644 // If kPreferredKeyboardLayout is not specified, use the hardware layout. | 569 // If kPreferredKeyboardLayout is not specified, use the hardware layout. |
| 645 input_methods_to_be_enabled = util_.GetHardwareLoginInputMethodIds(); | 570 input_methods_to_be_enabled = |
| 571 manager_->util_.GetHardwareLoginInputMethodIds(); |
| 646 } else { | 572 } else { |
| 647 input_methods_to_be_enabled.push_back(initial_input_method_id); | 573 input_methods_to_be_enabled.push_back(initial_input_method_id); |
| 648 } | 574 } |
| 649 EnableLoginLayouts(locale, input_methods_to_be_enabled); | 575 EnableLoginLayouts(locale, input_methods_to_be_enabled); |
| 650 LoadNecessaryComponentExtensions(); | 576 manager_->LoadNecessaryComponentExtensions(this); |
| 651 } | 577 } |
| 652 } | 578 } |
| 653 | 579 |
| 654 bool InputMethodManagerImpl::SwitchToNextInputMethod() { | 580 bool InputMethodManagerImpl::StateImpl::SwitchToNextInputMethod() { |
| 655 // Sanity checks. | 581 // Sanity checks. |
| 656 if (active_input_method_ids_.empty()) { | 582 if (active_input_method_ids.empty()) { |
| 657 DVLOG(1) << "active input method is empty"; | 583 DVLOG(1) << "active input method is empty"; |
| 658 return false; | 584 return false; |
| 659 } | 585 } |
| 660 | 586 |
| 661 if (current_input_method_.id().empty()) { | 587 if (current_input_method.id().empty()) { |
| 662 DVLOG(1) << "current_input_method_ is unknown"; | 588 DVLOG(1) << "current_input_method is unknown"; |
| 663 return false; | 589 return false; |
| 664 } | 590 } |
| 665 | 591 |
| 666 // Do not consume key event if there is only one input method is enabled. | 592 // Do not consume key event if there is only one input method is enabled. |
| 667 // Ctrl+Space or Alt+Shift may be used by other application. | 593 // Ctrl+Space or Alt+Shift may be used by other application. |
| 668 if (active_input_method_ids_.size() == 1) | 594 if (active_input_method_ids.size() == 1) |
| 669 return false; | 595 return false; |
| 670 | 596 |
| 671 // Find the next input method and switch to it. | 597 // Find the next input method and switch to it. |
| 672 SwitchToNextInputMethodInternal(active_input_method_ids_, | 598 SwitchToNextInputMethodInternal(active_input_method_ids, |
| 673 current_input_method_.id()); | 599 current_input_method.id()); |
| 674 return true; | 600 return true; |
| 675 } | 601 } |
| 676 | 602 |
| 677 bool InputMethodManagerImpl::SwitchToPreviousInputMethod( | 603 bool InputMethodManagerImpl::StateImpl::SwitchToPreviousInputMethod( |
| 678 const ui::Accelerator& accelerator) { | 604 const ui::Accelerator& accelerator) { |
| 679 // Sanity check. | 605 // Sanity check. |
| 680 if (active_input_method_ids_.empty()) { | 606 if (active_input_method_ids.empty()) { |
| 681 DVLOG(1) << "active input method is empty"; | 607 DVLOG(1) << "active input method is empty"; |
| 682 return false; | 608 return false; |
| 683 } | 609 } |
| 684 | 610 |
| 685 // Do not consume key event if there is only one input method is enabled. | 611 // Do not consume key event if there is only one input method is enabled. |
| 686 // Ctrl+Space or Alt+Shift may be used by other application. | 612 // Ctrl+Space or Alt+Shift may be used by other application. |
| 687 if (active_input_method_ids_.size() == 1) | 613 if (active_input_method_ids.size() == 1) |
| 688 return false; | 614 return false; |
| 689 | 615 |
| 690 if (accelerator.type() == ui::ET_KEY_RELEASED) | 616 if (accelerator.type() == ui::ET_KEY_RELEASED) |
| 691 return true; | 617 return true; |
| 692 | 618 |
| 693 if (previous_input_method_.id().empty() || | 619 if (previous_input_method.id().empty() || |
| 694 previous_input_method_.id() == current_input_method_.id()) { | 620 previous_input_method.id() == current_input_method.id()) { |
| 695 return SwitchToNextInputMethod(); | 621 return SwitchToNextInputMethod(); |
| 696 } | 622 } |
| 697 | 623 |
| 698 std::vector<std::string>::const_iterator iter = | 624 std::vector<std::string>::const_iterator iter = |
| 699 std::find(active_input_method_ids_.begin(), | 625 std::find(active_input_method_ids.begin(), |
| 700 active_input_method_ids_.end(), | 626 active_input_method_ids.end(), |
| 701 previous_input_method_.id()); | 627 previous_input_method.id()); |
| 702 if (iter == active_input_method_ids_.end()) { | 628 if (iter == active_input_method_ids.end()) { |
| 703 // previous_input_method_ is not supported. | 629 // previous_input_method is not supported. |
| 704 return SwitchToNextInputMethod(); | 630 return SwitchToNextInputMethod(); |
| 705 } | 631 } |
| 706 ChangeInputMethodInternal(*iter, true); | 632 ChangeInputMethod(*iter, true); |
| 633 |
| 707 return true; | 634 return true; |
| 708 } | 635 } |
| 709 | 636 |
| 710 bool InputMethodManagerImpl::SwitchInputMethod( | 637 bool InputMethodManagerImpl::StateImpl::SwitchInputMethod( |
| 711 const ui::Accelerator& accelerator) { | 638 const ui::Accelerator& accelerator) { |
| 712 // Sanity check. | 639 // Sanity check. |
| 713 if (active_input_method_ids_.empty()) { | 640 if (active_input_method_ids.empty()) { |
| 714 DVLOG(1) << "active input method is empty"; | 641 DVLOG(1) << "active input method is empty"; |
| 715 return false; | 642 return false; |
| 716 } | 643 } |
| 717 | 644 |
| 718 // Get the list of input method ids for the |accelerator|. For example, get | 645 // Get the list of input method ids for the |accelerator|. For example, get |
| 719 // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR. | 646 // { "mozc-hangul", "xkb:kr:kr104:kor" } for ui::VKEY_DBE_SBCSCHAR. |
| 720 std::vector<std::string> input_method_ids_to_switch; | 647 std::vector<std::string> input_method_ids_to_switch; |
| 721 switch (accelerator.key_code()) { | 648 switch (accelerator.key_code()) { |
| 722 case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard | 649 case ui::VKEY_CONVERT: // Henkan key on JP106 keyboard |
| 723 input_method_ids_to_switch.push_back( | 650 input_method_ids_to_switch.push_back( |
| (...skipping 13 matching lines...) Expand all Loading... |
| 737 default: | 664 default: |
| 738 NOTREACHED(); | 665 NOTREACHED(); |
| 739 break; | 666 break; |
| 740 } | 667 } |
| 741 if (input_method_ids_to_switch.empty()) { | 668 if (input_method_ids_to_switch.empty()) { |
| 742 DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code(); | 669 DVLOG(1) << "Unexpected VKEY: " << accelerator.key_code(); |
| 743 return false; | 670 return false; |
| 744 } | 671 } |
| 745 | 672 |
| 746 // Obtain the intersection of input_method_ids_to_switch and | 673 // Obtain the intersection of input_method_ids_to_switch and |
| 747 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is | 674 // active_input_method_ids. The order of IDs in active_input_method_ids is |
| 748 // preserved. | 675 // preserved. |
| 749 std::vector<std::string> ids; | 676 std::vector<std::string> ids; |
| 750 for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) { | 677 for (size_t i = 0; i < input_method_ids_to_switch.size(); ++i) { |
| 751 const std::string& id = input_method_ids_to_switch[i]; | 678 const std::string& id = input_method_ids_to_switch[i]; |
| 752 if (Contains(active_input_method_ids_, id)) | 679 if (Contains(active_input_method_ids, id)) |
| 753 ids.push_back(id); | 680 ids.push_back(id); |
| 754 } | 681 } |
| 755 if (ids.empty()) { | 682 if (ids.empty()) { |
| 756 // No input method for the accelerator is active. For example, we should | 683 // No input method for the accelerator is active. For example, we should |
| 757 // just ignore VKEY_HANGUL when mozc-hangul is not active. | 684 // just ignore VKEY_HANGUL when mozc-hangul is not active. |
| 758 return false; | 685 return false; |
| 759 } | 686 } |
| 760 | 687 |
| 761 SwitchToNextInputMethodInternal(ids, current_input_method_.id()); | 688 SwitchToNextInputMethodInternal(ids, current_input_method.id()); |
| 762 return true; // consume the accelerator. | 689 return true; // consume the accelerator. |
| 763 } | 690 } |
| 764 | 691 |
| 765 void InputMethodManagerImpl::SwitchToNextInputMethodInternal( | 692 void InputMethodManagerImpl::StateImpl::SwitchToNextInputMethodInternal( |
| 766 const std::vector<std::string>& input_method_ids, | 693 const std::vector<std::string>& input_method_ids, |
| 767 const std::string& current_input_method_id) { | 694 const std::string& current_input_methodid) { |
| 768 std::vector<std::string>::const_iterator iter = | 695 std::vector<std::string>::const_iterator iter = std::find( |
| 769 std::find(input_method_ids.begin(), | 696 input_method_ids.begin(), input_method_ids.end(), current_input_methodid); |
| 770 input_method_ids.end(), | |
| 771 current_input_method_id); | |
| 772 if (iter != input_method_ids.end()) | 697 if (iter != input_method_ids.end()) |
| 773 ++iter; | 698 ++iter; |
| 774 if (iter == input_method_ids.end()) | 699 if (iter == input_method_ids.end()) |
| 775 iter = input_method_ids.begin(); | 700 iter = input_method_ids.begin(); |
| 776 ChangeInputMethodInternal(*iter, true); | 701 ChangeInputMethod(*iter, true); |
| 777 } | 702 } |
| 778 | 703 |
| 779 InputMethodDescriptor InputMethodManagerImpl::GetCurrentInputMethod() const { | 704 InputMethodDescriptor InputMethodManagerImpl::StateImpl::GetCurrentInputMethod() |
| 780 if (current_input_method_.id().empty()) | 705 const { |
| 706 if (current_input_method.id().empty()) |
| 781 return InputMethodUtil::GetFallbackInputMethodDescriptor(); | 707 return InputMethodUtil::GetFallbackInputMethodDescriptor(); |
| 782 | 708 |
| 783 return current_input_method_; | 709 return current_input_method; |
| 710 } |
| 711 |
| 712 bool InputMethodManagerImpl::StateImpl::InputMethodIsActivated( |
| 713 const std::string& input_method_id) const { |
| 714 return Contains(active_input_method_ids, input_method_id); |
| 715 } |
| 716 |
| 717 // ------------------------ InputMethodManagerImpl |
| 718 bool InputMethodManagerImpl::IsLoginKeyboard( |
| 719 const std::string& layout) const { |
| 720 return util_.IsLoginKeyboard(layout); |
| 721 } |
| 722 |
| 723 bool InputMethodManagerImpl::MigrateInputMethods( |
| 724 std::vector<std::string>* input_method_ids) { |
| 725 return util_.MigrateInputMethods(input_method_ids); |
| 726 } |
| 727 |
| 728 // Starts or stops the system input method framework as needed. |
| 729 void InputMethodManagerImpl::ReconfigureIMFramework( |
| 730 InputMethodManagerImpl::StateImpl* state) { |
| 731 LoadNecessaryComponentExtensions(state); |
| 732 |
| 733 // Initialize candidate window controller and widgets such as |
| 734 // candidate window, infolist and mode indicator. Note, mode |
| 735 // indicator is used by only keyboard layout input methods. |
| 736 if (state_.get() == state) |
| 737 MaybeInitializeCandidateWindowController(); |
| 738 } |
| 739 |
| 740 void InputMethodManagerImpl::SetState( |
| 741 scoped_refptr<InputMethodManager::State> state) { |
| 742 DCHECK(state); |
| 743 InputMethodManagerImpl::StateImpl* new_impl_state = |
| 744 static_cast<InputMethodManagerImpl::StateImpl*>(state.get()); |
| 745 const bool need_update_current_input_method = |
| 746 (state_ ? state_->current_input_method.id() != |
| 747 new_impl_state->current_input_method.id() |
| 748 : true); |
| 749 state_ = new_impl_state; |
| 750 |
| 751 if (state_ && state_->active_input_method_ids.size()) { |
| 752 // Initialize candidate window controller and widgets such as |
| 753 // candidate window, infolist and mode indicator. Note, mode |
| 754 // indicator is used by only keyboard layout input methods. |
| 755 MaybeInitializeCandidateWindowController(); |
| 756 |
| 757 if (need_update_current_input_method) |
| 758 ChangeInputMethodInternal(state_->current_input_method, |
| 759 false /* show_message */, |
| 760 true /* notify_menu */); |
| 761 } |
| 762 } |
| 763 |
| 764 scoped_refptr<InputMethodManager::State> |
| 765 InputMethodManagerImpl::GetActiveIMEState() { |
| 766 return scoped_refptr<InputMethodManager::State>(state_.get()); |
| 767 } |
| 768 |
| 769 InputMethodManagerImpl::InputMethodManagerImpl( |
| 770 scoped_ptr<InputMethodDelegate> delegate, |
| 771 bool enable_extension_loading) |
| 772 : delegate_(delegate.Pass()), |
| 773 ui_session_(STATE_LOGIN_SCREEN), |
| 774 state_(NULL), |
| 775 util_(delegate_.get()), |
| 776 component_extension_ime_manager_(new ComponentExtensionIMEManager()), |
| 777 enable_extension_loading_(enable_extension_loading) { |
| 778 if (base::SysInfo::IsRunningOnChromeOS()) |
| 779 keyboard_.reset(ImeKeyboard::Create()); |
| 780 else |
| 781 keyboard_.reset(new FakeImeKeyboard()); |
| 782 |
| 783 // Initializes the system IME list. |
| 784 scoped_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate( |
| 785 new ComponentExtensionIMEManagerImpl()); |
| 786 component_extension_ime_manager_->Initialize(comp_delegate.Pass()); |
| 787 util_.ResetInputMethods( |
| 788 component_extension_ime_manager_->GetAllIMEAsInputMethodDescriptor()); |
| 789 } |
| 790 |
| 791 InputMethodManagerImpl::~InputMethodManagerImpl() { |
| 792 if (candidate_window_controller_.get()) |
| 793 candidate_window_controller_->RemoveObserver(this); |
| 794 } |
| 795 |
| 796 void InputMethodManagerImpl::AddObserver( |
| 797 InputMethodManager::Observer* observer) { |
| 798 observers_.AddObserver(observer); |
| 799 } |
| 800 |
| 801 void InputMethodManagerImpl::AddCandidateWindowObserver( |
| 802 InputMethodManager::CandidateWindowObserver* observer) { |
| 803 candidate_window_observers_.AddObserver(observer); |
| 804 } |
| 805 |
| 806 void InputMethodManagerImpl::RemoveObserver( |
| 807 InputMethodManager::Observer* observer) { |
| 808 observers_.RemoveObserver(observer); |
| 809 } |
| 810 |
| 811 void InputMethodManagerImpl::RemoveCandidateWindowObserver( |
| 812 InputMethodManager::CandidateWindowObserver* observer) { |
| 813 candidate_window_observers_.RemoveObserver(observer); |
| 814 } |
| 815 |
| 816 InputMethodManager::UISessionState InputMethodManagerImpl::GetUISessionState() { |
| 817 return ui_session_; |
| 818 } |
| 819 |
| 820 void InputMethodManagerImpl::SetUISessionState(UISessionState new_ui_session) { |
| 821 ui_session_ = new_ui_session; |
| 822 switch (ui_session_) { |
| 823 case STATE_LOGIN_SCREEN: |
| 824 break; |
| 825 case STATE_BROWSER_SCREEN: |
| 826 break; |
| 827 case STATE_LOCK_SCREEN: |
| 828 break; |
| 829 case STATE_TERMINATING: { |
| 830 if (candidate_window_controller_.get()) |
| 831 candidate_window_controller_.reset(); |
| 832 break; |
| 833 } |
| 834 } |
| 835 } |
| 836 |
| 837 scoped_ptr<InputMethodDescriptors> |
| 838 InputMethodManagerImpl::GetSupportedInputMethods() const { |
| 839 return scoped_ptr<InputMethodDescriptors>(new InputMethodDescriptors).Pass(); |
| 840 } |
| 841 |
| 842 const InputMethodDescriptor* InputMethodManagerImpl::LookupInputMethod( |
| 843 const std::string& input_method_id, |
| 844 InputMethodManagerImpl::StateImpl* state) { |
| 845 DCHECK(state); |
| 846 |
| 847 std::string input_method_id_to_switch = input_method_id; |
| 848 |
| 849 // Sanity check |
| 850 if (!state->InputMethodIsActivated(input_method_id)) { |
| 851 scoped_ptr<InputMethodDescriptors> input_methods( |
| 852 state->GetActiveInputMethods()); |
| 853 DCHECK(!input_methods->empty()); |
| 854 input_method_id_to_switch = input_methods->at(0).id(); |
| 855 if (!input_method_id.empty()) { |
| 856 DVLOG(1) << "Can't change the current input method to " |
| 857 << input_method_id << " since the engine is not enabled. " |
| 858 << "Switch to " << input_method_id_to_switch << " instead."; |
| 859 } |
| 860 } |
| 861 |
| 862 const InputMethodDescriptor* descriptor = NULL; |
| 863 if (extension_ime_util::IsExtensionIME(input_method_id_to_switch)) { |
| 864 DCHECK(state->extra_input_methods.find(input_method_id_to_switch) != |
| 865 state->extra_input_methods.end()); |
| 866 descriptor = &(state->extra_input_methods[input_method_id_to_switch]); |
| 867 } else { |
| 868 descriptor = |
| 869 util_.GetInputMethodDescriptorFromId(input_method_id_to_switch); |
| 870 if (!descriptor) |
| 871 LOG(ERROR) << "Unknown input method id: " << input_method_id_to_switch; |
| 872 } |
| 873 DCHECK(descriptor); |
| 874 return descriptor; |
| 875 } |
| 876 |
| 877 void InputMethodManagerImpl::ChangeInputMethodInternal( |
| 878 const InputMethodDescriptor& descriptor, |
| 879 bool show_message, |
| 880 bool notify_menu) { |
| 881 // No need to switch input method when terminating. |
| 882 if (ui_session_ == STATE_TERMINATING) |
| 883 return; |
| 884 |
| 885 if (candidate_window_controller_.get()) |
| 886 candidate_window_controller_->Hide(); |
| 887 |
| 888 if (notify_menu) { |
| 889 // Clear property list. Property list would be updated by |
| 890 // extension IMEs via InputMethodEngine::(Set|Update)MenuItems. |
| 891 // If the current input method is a keyboard layout, empty |
| 892 // properties are sufficient. |
| 893 const ash::ime::InputMethodMenuItemList empty_menu_item_list; |
| 894 ash::ime::InputMethodMenuManager* input_method_menu_manager = |
| 895 ash::ime::InputMethodMenuManager::GetInstance(); |
| 896 input_method_menu_manager->SetCurrentInputMethodMenuItemList( |
| 897 empty_menu_item_list); |
| 898 } |
| 899 |
| 900 // Disable the current engine handler. |
| 901 IMEEngineHandlerInterface* engine = |
| 902 IMEBridge::Get()->GetCurrentEngineHandler(); |
| 903 if (engine) |
| 904 engine->Disable(); |
| 905 |
| 906 // Configure the next engine handler. |
| 907 // This must be after |current_input_method| has been set to new input |
| 908 // method, because engine's Enable() method needs to access it. |
| 909 const std::string& extension_id = |
| 910 extension_ime_util::GetExtensionIDFromInputMethodID(descriptor.id()); |
| 911 const std::string& component_id = |
| 912 extension_ime_util::GetComponentIDByInputMethodID(descriptor.id()); |
| 913 engine = engine_map_[extension_id]; |
| 914 |
| 915 IMEBridge::Get()->SetCurrentEngineHandler(engine); |
| 916 |
| 917 if (engine) |
| 918 engine->Enable(component_id); |
| 919 |
| 920 // Change the keyboard layout to a preferred layout for the input method. |
| 921 if (!keyboard_->SetCurrentKeyboardLayoutByName( |
| 922 descriptor.GetPreferredKeyboardLayout())) { |
| 923 LOG(ERROR) << "Failed to change keyboard layout to " |
| 924 << descriptor.GetPreferredKeyboardLayout(); |
| 925 } |
| 926 |
| 927 // Update input method indicators (e.g. "US", "DV") in Chrome windows. |
| 928 FOR_EACH_OBSERVER(InputMethodManager::Observer, |
| 929 observers_, |
| 930 InputMethodChanged(this, show_message)); |
| 931 } |
| 932 |
| 933 void InputMethodManagerImpl::LoadNecessaryComponentExtensions( |
| 934 InputMethodManagerImpl::StateImpl* state) { |
| 935 // Load component extensions but also update |active_input_method_ids| as |
| 936 // some component extension IMEs may have been removed from the Chrome OS |
| 937 // image. If specified component extension IME no longer exists, falling back |
| 938 // to an existing IME. |
| 939 DCHECK(state); |
| 940 std::vector<std::string> unfiltered_input_method_ids; |
| 941 unfiltered_input_method_ids.swap(state->active_input_method_ids); |
| 942 for (size_t i = 0; i < unfiltered_input_method_ids.size(); ++i) { |
| 943 if (!extension_ime_util::IsComponentExtensionIME( |
| 944 unfiltered_input_method_ids[i])) { |
| 945 // Legacy IMEs or xkb layouts are alwayes active. |
| 946 state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]); |
| 947 } else if (component_extension_ime_manager_->IsWhitelisted( |
| 948 unfiltered_input_method_ids[i])) { |
| 949 if (enable_extension_loading_) { |
| 950 component_extension_ime_manager_->LoadComponentExtensionIME( |
| 951 state->profile, unfiltered_input_method_ids[i]); |
| 952 } |
| 953 |
| 954 state->active_input_method_ids.push_back(unfiltered_input_method_ids[i]); |
| 955 } |
| 956 } |
| 957 } |
| 958 |
| 959 void InputMethodManagerImpl::ActivateInputMethodMenuItem( |
| 960 const std::string& key) { |
| 961 DCHECK(!key.empty()); |
| 962 |
| 963 if (ash::ime::InputMethodMenuManager::GetInstance()-> |
| 964 HasInputMethodMenuItemForKey(key)) { |
| 965 IMEEngineHandlerInterface* engine = |
| 966 IMEBridge::Get()->GetCurrentEngineHandler(); |
| 967 if (engine) |
| 968 engine->PropertyActivate(key); |
| 969 return; |
| 970 } |
| 971 |
| 972 DVLOG(1) << "ActivateInputMethodMenuItem: unknown key: " << key; |
| 784 } | 973 } |
| 785 | 974 |
| 786 bool InputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod() const { | 975 bool InputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod() const { |
| 787 return keyboard_->IsISOLevel5ShiftAvailable(); | 976 return keyboard_->IsISOLevel5ShiftAvailable(); |
| 788 } | 977 } |
| 789 | 978 |
| 790 bool InputMethodManagerImpl::IsAltGrUsedByCurrentInputMethod() const { | 979 bool InputMethodManagerImpl::IsAltGrUsedByCurrentInputMethod() const { |
| 791 return keyboard_->IsAltGrAvailable(); | 980 return keyboard_->IsAltGrAvailable(); |
| 792 } | 981 } |
| 793 | 982 |
| 794 ImeKeyboard* InputMethodManagerImpl::GetImeKeyboard() { | 983 ImeKeyboard* InputMethodManagerImpl::GetImeKeyboard() { |
| 795 return keyboard_.get(); | 984 return keyboard_.get(); |
| 796 } | 985 } |
| 797 | 986 |
| 798 InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() { | 987 InputMethodUtil* InputMethodManagerImpl::GetInputMethodUtil() { |
| 799 return &util_; | 988 return &util_; |
| 800 } | 989 } |
| 801 | 990 |
| 802 ComponentExtensionIMEManager* | 991 ComponentExtensionIMEManager* |
| 803 InputMethodManagerImpl::GetComponentExtensionIMEManager() { | 992 InputMethodManagerImpl::GetComponentExtensionIMEManager() { |
| 804 return component_extension_ime_manager_.get(); | 993 return component_extension_ime_manager_.get(); |
| 805 } | 994 } |
| 806 | 995 |
| 996 scoped_refptr<InputMethodManager::State> InputMethodManagerImpl::CreateNewState( |
| 997 Profile* profile) { |
| 998 return scoped_refptr<InputMethodManager::State>(new StateImpl(this, profile)); |
| 999 } |
| 1000 |
| 807 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting( | 1001 void InputMethodManagerImpl::SetCandidateWindowControllerForTesting( |
| 808 CandidateWindowController* candidate_window_controller) { | 1002 CandidateWindowController* candidate_window_controller) { |
| 809 candidate_window_controller_.reset(candidate_window_controller); | 1003 candidate_window_controller_.reset(candidate_window_controller); |
| 810 candidate_window_controller_->AddObserver(this); | 1004 candidate_window_controller_->AddObserver(this); |
| 811 } | 1005 } |
| 812 | 1006 |
| 813 void InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) { | 1007 void InputMethodManagerImpl::SetImeKeyboardForTesting(ImeKeyboard* keyboard) { |
| 814 keyboard_.reset(keyboard); | 1008 keyboard_.reset(keyboard); |
| 815 } | 1009 } |
| 816 | 1010 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 833 candidate_window_observers_, | 1027 candidate_window_observers_, |
| 834 CandidateWindowOpened(this)); | 1028 CandidateWindowOpened(this)); |
| 835 } | 1029 } |
| 836 | 1030 |
| 837 void InputMethodManagerImpl::CandidateWindowClosed() { | 1031 void InputMethodManagerImpl::CandidateWindowClosed() { |
| 838 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver, | 1032 FOR_EACH_OBSERVER(InputMethodManager::CandidateWindowObserver, |
| 839 candidate_window_observers_, | 1033 candidate_window_observers_, |
| 840 CandidateWindowClosed(this)); | 1034 CandidateWindowClosed(this)); |
| 841 } | 1035 } |
| 842 | 1036 |
| 843 void InputMethodManagerImpl::OnScreenLocked() { | |
| 844 saved_previous_input_method_ = previous_input_method_; | |
| 845 saved_current_input_method_ = current_input_method_; | |
| 846 saved_active_input_method_ids_ = active_input_method_ids_; | |
| 847 | |
| 848 std::set<std::string> added_ids_; | |
| 849 | |
| 850 const std::vector<std::string>& hardware_keyboard_ids = | |
| 851 util_.GetHardwareLoginInputMethodIds(); | |
| 852 | |
| 853 active_input_method_ids_.clear(); | |
| 854 for (size_t i = 0; i < saved_active_input_method_ids_.size(); ++i) { | |
| 855 const std::string& input_method_id = saved_active_input_method_ids_[i]; | |
| 856 // Skip if it's not a keyboard layout. Drop input methods including | |
| 857 // extension ones. | |
| 858 if (!IsLoginKeyboard(input_method_id) || | |
| 859 added_ids_.find(input_method_id) != added_ids_.end()) | |
| 860 continue; | |
| 861 active_input_method_ids_.push_back(input_method_id); | |
| 862 added_ids_.insert(input_method_id); | |
| 863 } | |
| 864 | |
| 865 // We'll add the hardware keyboard if it's not included in | |
| 866 // |active_input_method_ids_| so that the user can always use the hardware | |
| 867 // keyboard on the screen locker. | |
| 868 for (size_t i = 0; i < hardware_keyboard_ids.size(); ++i) { | |
| 869 if (added_ids_.find(hardware_keyboard_ids[i]) == added_ids_.end()) { | |
| 870 active_input_method_ids_.push_back(hardware_keyboard_ids[i]); | |
| 871 added_ids_.insert(hardware_keyboard_ids[i]); | |
| 872 } | |
| 873 } | |
| 874 | |
| 875 ChangeInputMethod(current_input_method_.id()); | |
| 876 } | |
| 877 | |
| 878 void InputMethodManagerImpl::OnScreenUnlocked() { | |
| 879 previous_input_method_ = saved_previous_input_method_; | |
| 880 current_input_method_ = saved_current_input_method_; | |
| 881 active_input_method_ids_ = saved_active_input_method_ids_; | |
| 882 | |
| 883 ChangeInputMethod(current_input_method_.id()); | |
| 884 } | |
| 885 | |
| 886 bool InputMethodManagerImpl::InputMethodIsActivated( | |
| 887 const std::string& input_method_id) { | |
| 888 return Contains(active_input_method_ids_, input_method_id); | |
| 889 } | |
| 890 | |
| 891 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() { | 1037 void InputMethodManagerImpl::MaybeInitializeCandidateWindowController() { |
| 892 if (candidate_window_controller_.get()) | 1038 if (candidate_window_controller_.get()) |
| 893 return; | 1039 return; |
| 894 | 1040 |
| 895 candidate_window_controller_.reset( | 1041 candidate_window_controller_.reset( |
| 896 CandidateWindowController::CreateCandidateWindowController()); | 1042 CandidateWindowController::CreateCandidateWindowController()); |
| 897 candidate_window_controller_->AddObserver(this); | 1043 candidate_window_controller_->AddObserver(this); |
| 898 } | 1044 } |
| 899 | 1045 |
| 900 } // namespace input_method | 1046 } // namespace input_method |
| 901 } // namespace chromeos | 1047 } // namespace chromeos |
| OLD | NEW |