input_method_api.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/input_method_api.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/extensions/input_method_event_router.h"
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/chromeos/input_method/input_method_util.h"
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chromeos/ime/extension_ime_util.h"
13f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chromeos/ime/input_method_descriptor.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chromeos/ime/input_method_manager.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/extension_function_registry.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
17f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "extensions/common/value_builder.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Prefix, which is used by XKB.
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kXkbPrefix[] = "xkb:";
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ExtensionFunction::ResponseAction GetCurrentInputMethodFunction::Run() {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if !defined(OS_CHROMEOS)
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(false);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chromeos::input_method::InputMethodManager* manager =
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      chromeos::input_method::InputMethodManager::Get();
3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return RespondNow(OneArgument(new base::StringValue(
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager->GetActiveIMEState()->GetCurrentInputMethod().id())));
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ExtensionFunction::ResponseAction SetCurrentInputMethodFunction::Run() {
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if !defined(OS_CHROMEOS)
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(false);
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#else
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string new_input_method;
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &new_input_method));
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<chromeos::input_method::InputMethodManager::State> ime_state =
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      chromeos::input_method::InputMethodManager::Get()->GetActiveIMEState();
47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const std::vector<std::string>& input_methods =
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ime_state->GetActiveInputMethodIds();
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < input_methods.size(); ++i) {
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& input_method = input_methods[i];
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (input_method == new_input_method) {
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ime_state->ChangeInputMethod(new_input_method, false /* show_message */);
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return RespondNow(NoArguments());
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return RespondNow(Error("Invalid input method id."));
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)ExtensionFunction::ResponseAction GetInputMethodsFunction::Run() {
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if !defined(OS_CHROMEOS)
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(false);
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#else
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::ListValue* output = new base::ListValue();
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  chromeos::input_method::InputMethodManager* manager =
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      chromeos::input_method::InputMethodManager::Get();
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  chromeos::input_method::InputMethodUtil* util = manager->GetInputMethodUtil();
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_refptr<chromeos::input_method::InputMethodManager::State> ime_state =
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      manager->GetActiveIMEState();
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<chromeos::input_method::InputMethodDescriptors> input_methods =
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      ime_state->GetActiveInputMethods();
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < input_methods->size(); ++i) {
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const chromeos::input_method::InputMethodDescriptor& input_method =
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        (*input_methods)[i];
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    base::DictionaryValue* val = new base::DictionaryValue();
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    val->SetString("id", input_method.id());
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    val->SetString("name", util->GetInputMethodLongName(input_method));
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    val->SetString("indicator", util->GetInputMethodShortName(input_method));
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    output->Append(val);
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return RespondNow(OneArgument(output));
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char InputMethodAPI::kOnInputMethodChanged[] =
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    "inputMethodPrivate.onChanged";
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)InputMethodAPI::InputMethodAPI(content::BrowserContext* context)
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : context_(context) {
910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(context_)->RegisterObserver(this, kOnInputMethodChanged);
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ExtensionFunctionRegistry* registry =
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ExtensionFunctionRegistry::GetInstance();
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registry->RegisterFunction<GetCurrentInputMethodFunction>();
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registry->RegisterFunction<SetCurrentInputMethodFunction>();
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  registry->RegisterFunction<GetInputMethodsFunction>();
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputMethodAPI::~InputMethodAPI() {
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)std::string InputMethodAPI::GetInputMethodForXkb(const std::string& xkb_id) {
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string xkb_prefix =
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      chromeos::extension_ime_util::GetInputMethodIDByEngineID(kXkbPrefix);
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  size_t prefix_length = xkb_prefix.length();
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(xkb_id.substr(0, prefix_length) == xkb_prefix);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return xkb_id.substr(prefix_length);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputMethodAPI::Shutdown() {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // UnregisterObserver may have already been called in OnListenerAdded,
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // but it is safe to call it more than once.
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(context_)->UnregisterObserver(this);
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void InputMethodAPI::OnListenerAdded(
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const extensions::EventListenerInfo& details) {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!input_method_event_router_.get());
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  input_method_event_router_.reset(
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new chromeos::ExtensionInputMethodEventRouter(context_));
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EventRouter::Get(context_)->UnregisterObserver(this);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<InputMethodAPI> >
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<InputMethodAPI>*
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)InputMethodAPI::GetFactoryInstance() {
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
135