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/extensions/input_method_api.h"
7 #include "base/command_line.h"
8 #include "base/lazy_instance.h"
9 #include "base/values.h"
10 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
11 #include "chrome/browser/chromeos/input_method/input_method_util.h"
12 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
13 #include "chrome/browser/spellchecker/spellcheck_factory.h"
14 #include "chrome/browser/spellchecker/spellcheck_service.h"
15 #include "chromeos/chromeos_switches.h"
16 #include "extensions/browser/extension_function_registry.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/common/value_builder.h"
19 #include "ui/base/ime/chromeos/extension_ime_util.h"
20 #include "ui/base/ime/chromeos/input_method_descriptor.h"
21 #include "ui/base/ime/chromeos/input_method_manager.h"
25 // Prefix, which is used by XKB.
26 const char kXkbPrefix
[] = "xkb:";
30 namespace extensions
{
32 ExtensionFunction::ResponseAction
GetInputMethodConfigFunction::Run() {
33 #if !defined(OS_CHROMEOS)
34 EXTENSION_FUNCTION_VALIDATE(false);
36 base::DictionaryValue
* output
= new base::DictionaryValue();
38 "isPhysicalKeyboardAutocorrectEnabled",
39 base::CommandLine::ForCurrentProcess()->HasSwitch(
40 chromeos::switches::kEnablePhysicalKeyboardAutocorrect
));
41 output
->SetBoolean("isVoiceInputEnabled",
42 !base::CommandLine::ForCurrentProcess()->HasSwitch(
43 chromeos::switches::kDisableVoiceInput
));
44 output
->SetBoolean("isNewMDInputViewEnabled",
45 base::CommandLine::ForCurrentProcess()->HasSwitch(
46 chromeos::switches::kEnableNewMDInputView
));
47 return RespondNow(OneArgument(output
));
51 ExtensionFunction::ResponseAction
GetCurrentInputMethodFunction::Run() {
52 #if !defined(OS_CHROMEOS)
53 EXTENSION_FUNCTION_VALIDATE(false);
55 chromeos::input_method::InputMethodManager
* manager
=
56 chromeos::input_method::InputMethodManager::Get();
57 return RespondNow(OneArgument(new base::StringValue(
58 manager
->GetActiveIMEState()->GetCurrentInputMethod().id())));
62 ExtensionFunction::ResponseAction
SetCurrentInputMethodFunction::Run() {
63 #if !defined(OS_CHROMEOS)
64 EXTENSION_FUNCTION_VALIDATE(false);
66 std::string new_input_method
;
67 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &new_input_method
));
68 scoped_refptr
<chromeos::input_method::InputMethodManager::State
> ime_state
=
69 chromeos::input_method::InputMethodManager::Get()->GetActiveIMEState();
70 const std::vector
<std::string
>& input_methods
=
71 ime_state
->GetActiveInputMethodIds();
72 for (size_t i
= 0; i
< input_methods
.size(); ++i
) {
73 const std::string
& input_method
= input_methods
[i
];
74 if (input_method
== new_input_method
) {
75 ime_state
->ChangeInputMethod(new_input_method
, false /* show_message */);
76 return RespondNow(NoArguments());
79 return RespondNow(Error("Invalid input method id."));
83 ExtensionFunction::ResponseAction
GetInputMethodsFunction::Run() {
84 #if !defined(OS_CHROMEOS)
85 EXTENSION_FUNCTION_VALIDATE(false);
87 base::ListValue
* output
= new base::ListValue();
88 chromeos::input_method::InputMethodManager
* manager
=
89 chromeos::input_method::InputMethodManager::Get();
90 chromeos::input_method::InputMethodUtil
* util
= manager
->GetInputMethodUtil();
91 scoped_refptr
<chromeos::input_method::InputMethodManager::State
> ime_state
=
92 manager
->GetActiveIMEState();
93 scoped_ptr
<chromeos::input_method::InputMethodDescriptors
> input_methods
=
94 ime_state
->GetActiveInputMethods();
95 for (size_t i
= 0; i
< input_methods
->size(); ++i
) {
96 const chromeos::input_method::InputMethodDescriptor
& input_method
=
98 base::DictionaryValue
* val
= new base::DictionaryValue();
99 val
->SetString("id", input_method
.id());
100 val
->SetString("name", util
->GetInputMethodLongName(input_method
));
101 val
->SetString("indicator", util
->GetInputMethodShortName(input_method
));
104 return RespondNow(OneArgument(output
));
108 ExtensionFunction::ResponseAction
FetchAllDictionaryWordsFunction::Run() {
109 #if !defined(OS_CHROMEOS)
110 EXTENSION_FUNCTION_VALIDATE(false);
112 SpellcheckService
* spellcheck
= SpellcheckServiceFactory::GetForContext(
115 return RespondNow(Error("Spellcheck service not available."));
117 SpellcheckCustomDictionary
* dictionary
= spellcheck
->GetCustomDictionary();
118 if (!dictionary
->IsLoaded()) {
119 return RespondNow(Error("Custom dictionary not loaded yet."));
122 const chrome::spellcheck_common::WordSet
& words
= dictionary
->GetWords();
123 base::ListValue
* output
= new base::ListValue();
124 for (auto it
= words
.begin(); it
!= words
.end(); ++it
) {
125 output
->AppendString(*it
);
127 return RespondNow(OneArgument(output
));
131 ExtensionFunction::ResponseAction
AddWordToDictionaryFunction::Run() {
132 #if !defined(OS_CHROMEOS)
133 EXTENSION_FUNCTION_VALIDATE(false);
136 EXTENSION_FUNCTION_VALIDATE(args_
->GetString(0, &word
));
137 SpellcheckService
* spellcheck
= SpellcheckServiceFactory::GetForContext(
140 return RespondNow(Error("Spellcheck service not available."));
142 SpellcheckCustomDictionary
* dictionary
= spellcheck
->GetCustomDictionary();
143 if (!dictionary
->IsLoaded()) {
144 return RespondNow(Error("Custom dictionary not loaded yet."));
147 if (dictionary
->AddWord(word
))
148 return RespondNow(NoArguments());
150 // - Already in the dictionary.
151 // - Not a UTF8 string.
152 // - Longer than 99 bytes (MAX_CUSTOM_DICTIONARY_WORD_BYTES).
153 // - Leading/trailing whitespace.
155 return RespondNow(Error("Unable to add invalid word to dictionary."));
160 const char InputMethodAPI::kOnInputMethodChanged
[] =
161 "inputMethodPrivate.onChanged";
163 InputMethodAPI::InputMethodAPI(content::BrowserContext
* context
)
164 : context_(context
) {
165 EventRouter::Get(context_
)->RegisterObserver(this, kOnInputMethodChanged
);
166 ExtensionFunctionRegistry
* registry
=
167 ExtensionFunctionRegistry::GetInstance();
168 registry
->RegisterFunction
<GetInputMethodConfigFunction
>();
169 registry
->RegisterFunction
<GetCurrentInputMethodFunction
>();
170 registry
->RegisterFunction
<SetCurrentInputMethodFunction
>();
171 registry
->RegisterFunction
<GetInputMethodsFunction
>();
172 registry
->RegisterFunction
<FetchAllDictionaryWordsFunction
>();
173 registry
->RegisterFunction
<AddWordToDictionaryFunction
>();
176 InputMethodAPI::~InputMethodAPI() {
180 std::string
InputMethodAPI::GetInputMethodForXkb(const std::string
& xkb_id
) {
181 std::string xkb_prefix
=
182 chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix
);
183 size_t prefix_length
= xkb_prefix
.length();
184 DCHECK(xkb_id
.substr(0, prefix_length
) == xkb_prefix
);
185 return xkb_id
.substr(prefix_length
);
188 void InputMethodAPI::Shutdown() {
189 // UnregisterObserver may have already been called in OnListenerAdded,
190 // but it is safe to call it more than once.
191 EventRouter::Get(context_
)->UnregisterObserver(this);
194 void InputMethodAPI::OnListenerAdded(
195 const extensions::EventListenerInfo
& details
) {
196 DCHECK(!input_method_event_router_
.get());
197 input_method_event_router_
.reset(
198 new chromeos::ExtensionInputMethodEventRouter(context_
));
199 EventRouter::Get(context_
)->UnregisterObserver(this);
202 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<InputMethodAPI
> >
203 g_factory
= LAZY_INSTANCE_INITIALIZER
;
206 BrowserContextKeyedAPIFactory
<InputMethodAPI
>*
207 InputMethodAPI::GetFactoryInstance() {
208 return g_factory
.Pointer();
211 } // namespace extensions