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"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/values.h"
13 #include "chrome/browser/chromeos/extensions/dictionary_event_router.h"
14 #include "chrome/browser/chromeos/extensions/input_method_event_router.h"
15 #include "chrome/browser/chromeos/input_method/input_method_util.h"
16 #include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
17 #include "chrome/browser/spellchecker/spellcheck_factory.h"
18 #include "chrome/browser/spellchecker/spellcheck_service.h"
19 #include "chrome/browser/sync/profile_sync_service.h"
20 #include "chrome/browser/sync/profile_sync_service_factory.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "extensions/browser/extension_function_registry.h"
23 #include "extensions/browser/extension_system.h"
24 #include "ui/base/ime/chromeos/extension_ime_util.h"
25 #include "ui/base/ime/chromeos/input_method_descriptor.h"
26 #include "ui/base/ime/chromeos/input_method_manager.h"
27 #include "ui/keyboard/keyboard_util.h"
31 // Prefix, which is used by XKB.
32 const char kXkbPrefix
[] = "xkb:";
36 namespace extensions
{
38 ExtensionFunction::ResponseAction
GetInputMethodConfigFunction::Run() {
39 #if !defined(OS_CHROMEOS)
40 EXTENSION_FUNCTION_VALIDATE(false);
42 base::DictionaryValue
* output
= new base::DictionaryValue();
44 "isPhysicalKeyboardAutocorrectEnabled",
45 !base::CommandLine::ForCurrentProcess()->HasSwitch(
46 chromeos::switches::kDisablePhysicalKeyboardAutocorrect
));
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 std::set
<std::string
>& 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."));
159 ExtensionFunction::ResponseAction
GetEncryptSyncEnabledFunction::Run() {
160 #if !defined(OS_CHROMEOS)
161 EXTENSION_FUNCTION_VALIDATE(false);
163 ProfileSyncService
* profile_sync_service
=
164 ProfileSyncServiceFactory::GetForProfile(
165 Profile::FromBrowserContext(browser_context()));
166 if (!profile_sync_service
)
167 return RespondNow(Error("Sync service is not ready for current profile."));
168 scoped_ptr
<base::Value
> ret(new base::FundamentalValue(
169 profile_sync_service
->IsEncryptEverythingEnabled()));
170 return RespondNow(OneArgument(ret
.Pass()));
175 const char InputMethodAPI::kOnDictionaryChanged
[] =
176 "inputMethodPrivate.onDictionaryChanged";
179 const char InputMethodAPI::kOnDictionaryLoaded
[] =
180 "inputMethodPrivate.onDictionaryLoaded";
183 const char InputMethodAPI::kOnInputMethodChanged
[] =
184 "inputMethodPrivate.onChanged";
186 InputMethodAPI::InputMethodAPI(content::BrowserContext
* context
)
187 : context_(context
) {
188 EventRouter::Get(context_
)->RegisterObserver(this, kOnInputMethodChanged
);
189 EventRouter::Get(context_
)->RegisterObserver(this, kOnDictionaryChanged
);
190 EventRouter::Get(context_
)->RegisterObserver(this, kOnDictionaryLoaded
);
191 ExtensionFunctionRegistry
* registry
=
192 ExtensionFunctionRegistry::GetInstance();
193 registry
->RegisterFunction
<GetInputMethodConfigFunction
>();
194 registry
->RegisterFunction
<GetCurrentInputMethodFunction
>();
195 registry
->RegisterFunction
<SetCurrentInputMethodFunction
>();
196 registry
->RegisterFunction
<GetInputMethodsFunction
>();
197 registry
->RegisterFunction
<FetchAllDictionaryWordsFunction
>();
198 registry
->RegisterFunction
<AddWordToDictionaryFunction
>();
199 registry
->RegisterFunction
<GetEncryptSyncEnabledFunction
>();
202 InputMethodAPI::~InputMethodAPI() {
206 std::string
InputMethodAPI::GetInputMethodForXkb(const std::string
& xkb_id
) {
207 std::string xkb_prefix
=
208 chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix
);
209 size_t prefix_length
= xkb_prefix
.length();
210 DCHECK(xkb_id
.substr(0, prefix_length
) == xkb_prefix
);
211 return xkb_id
.substr(prefix_length
);
214 void InputMethodAPI::Shutdown() {
215 EventRouter::Get(context_
)->UnregisterObserver(this);
218 void InputMethodAPI::OnListenerAdded(
219 const extensions::EventListenerInfo
& details
) {
220 if (details
.event_name
== kOnInputMethodChanged
) {
221 if (!input_method_event_router_
.get()) {
222 input_method_event_router_
.reset(
223 new chromeos::ExtensionInputMethodEventRouter(context_
));
225 } else if (details
.event_name
== kOnDictionaryChanged
||
226 details
.event_name
== kOnDictionaryLoaded
) {
227 if (!dictionary_event_router_
.get()) {
228 dictionary_event_router_
.reset(
229 new chromeos::ExtensionDictionaryEventRouter(context_
));
231 if (details
.event_name
== kOnDictionaryLoaded
) {
232 dictionary_event_router_
->DispatchLoadedEventIfLoaded();
237 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<InputMethodAPI
> >
238 g_factory
= LAZY_INSTANCE_INITIALIZER
;
241 BrowserContextKeyedAPIFactory
<InputMethodAPI
>*
242 InputMethodAPI::GetFactoryInstance() {
243 return g_factory
.Pointer();
246 } // namespace extensions