summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-12 07:01:27 +0000
committerzork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-12 07:01:27 +0000
commit817925aaf716cb623c56e21030650f075e510157 (patch)
tree7fa202867b8025e0556622a5c48143ec256860f3
parentc24e5d45e49e3241332b7df30d925ba684d35b61 (diff)
downloadchromium_src-817925aaf716cb623c56e21030650f075e510157.zip
chromium_src-817925aaf716cb623c56e21030650f075e510157.tar.gz
chromium_src-817925aaf716cb623c56e21030650f075e510157.tar.bz2
Implement SetMenuItems and UpdateMenuItems in the IME API
BUG=chromium-os:16090 TEST=Manual Review URL: http://codereview.chromium.org/8073022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@105027 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/input_method/ibus_engine_controller.cc332
-rw-r--r--chrome/browser/chromeos/input_method/ibus_engine_controller.h42
-rw-r--r--chrome/browser/chromeos/input_method/input_method_engine.cc288
-rw-r--r--chrome/browser/chromeos/input_method/input_method_engine.h16
-rw-r--r--chrome/browser/extensions/extension_input_ime_api.cc301
-rw-r--r--chrome/browser/extensions/extension_input_ime_api.h4
-rw-r--r--chrome/browser/extensions/extension_input_ime_apitest.cc17
-rw-r--r--chrome/browser/extensions/extension_input_module_constants.cc10
-rw-r--r--chrome/browser/extensions/extension_input_module_constants.h10
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/api/extension_api.json9
-rw-r--r--chrome/test/data/extensions/api_test/input_ime/background.html41
-rw-r--r--chrome/test/data/extensions/api_test/input_ime/manifest.json17
13 files changed, 930 insertions, 158 deletions
diff --git a/chrome/browser/chromeos/input_method/ibus_engine_controller.cc b/chrome/browser/chromeos/input_method/ibus_engine_controller.cc
index 7654bfd..9cc8edb 100644
--- a/chrome/browser/chromeos/input_method/ibus_engine_controller.cc
+++ b/chrome/browser/chromeos/input_method/ibus_engine_controller.cc
@@ -9,14 +9,25 @@
#endif
#include <map>
+#include <set>
#include <string>
#include <vector>
#include "base/logging.h"
+#include "base/stl_util.h"
namespace chromeos {
namespace input_method {
+IBusEngineController::EngineProperty::EngineProperty()
+ : sensitive(false), visible(false), type(PROPERTY_TYPE_NORMAL),
+ checked(false), modified(0) {
+}
+
+IBusEngineController::EngineProperty::~EngineProperty() {
+ STLDeleteContainerPointers(children.begin(), children.end());
+}
+
#if defined(HAVE_IBUS)
#define IBUS_TYPE_CHROMEOS_ENGINE (ibus_chromeos_engine_get_type())
@@ -55,7 +66,7 @@ class IBusEngineControllerImpl : public IBusEngineController {
explicit IBusEngineControllerImpl(IBusEngineController::Observer* observer)
: observer_(observer),
ibus_(NULL),
- engine_(NULL),
+ active_engine_(NULL),
preedit_text_(NULL),
preedit_cursor_(0),
table_visible_(false),
@@ -79,6 +90,7 @@ class IBusEngineControllerImpl : public IBusEngineController {
g_object_unref(ibus_);
}
g_connections_->erase(engine_id_);
+ ClearProperties();
VLOG(1) << "Removing engine: " << engine_id_;
}
@@ -128,7 +140,7 @@ class IBusEngineControllerImpl : public IBusEngineController {
}
virtual void SetPreeditText(const char* text, int cursor) {
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetPreeditText";
if (preedit_text_) {
g_object_unref(preedit_text_);
@@ -137,14 +149,15 @@ class IBusEngineControllerImpl : public IBusEngineController {
preedit_cursor_ = cursor;
preedit_text_ = static_cast<IBusText*>(
g_object_ref_sink(ibus_text_new_from_string(text)));
- ibus_engine_update_preedit_text(IBUS_ENGINE(engine_), preedit_text_,
+ ibus_engine_update_preedit_text(IBUS_ENGINE(active_engine_),
+ preedit_text_,
preedit_cursor_, TRUE);
}
}
virtual void SetPreeditUnderline(int start, int end, int type) {
VLOG(1) << "SetPreeditUnderline";
- if (engine_ && preedit_text_) {
+ if (active_engine_ && preedit_text_) {
// Translate the type to ibus's constants.
int underline_type;
switch (type) {
@@ -174,13 +187,14 @@ class IBusEngineControllerImpl : public IBusEngineController {
ibus_text_append_attribute(preedit_text_, IBUS_ATTR_TYPE_UNDERLINE,
underline_type, start, end);
- ibus_engine_update_preedit_text(IBUS_ENGINE(engine_), preedit_text_,
+ ibus_engine_update_preedit_text(IBUS_ENGINE(active_engine_),
+ preedit_text_,
preedit_cursor_, TRUE);
}
}
virtual void CommitText(const char* text) {
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "CommitText";
// Reset the preedit text when a commit occurs.
SetPreeditText("", 0);
@@ -189,62 +203,67 @@ class IBusEngineControllerImpl : public IBusEngineController {
preedit_text_ = NULL;
}
IBusText* ibus_text = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(text)));
- ibus_engine_commit_text(IBUS_ENGINE(engine_), ibus_text);
+ ibus_text_new_from_string(text));
+ ibus_engine_commit_text(IBUS_ENGINE(active_engine_), ibus_text);
}
}
virtual void SetTableVisible(bool visible) {
table_visible_ = visible;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetTableVisible";
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
if (visible) {
- ibus_engine_show_lookup_table(IBUS_ENGINE(engine_));
+ ibus_engine_show_lookup_table(IBUS_ENGINE(active_engine_));
} else {
- ibus_engine_hide_lookup_table(IBUS_ENGINE(engine_));
+ ibus_engine_hide_lookup_table(IBUS_ENGINE(active_engine_));
}
}
}
virtual void SetCursorVisible(bool visible) {
cursor_visible_ = visible;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetCursorVisible";
- ibus_lookup_table_set_cursor_visible(engine_->table, visible);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_lookup_table_set_cursor_visible(active_engine_->table, visible);
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void SetOrientationVertical(bool vertical) {
vertical_ = vertical;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetOrientationVertical";
- ibus_lookup_table_set_orientation(engine_->table,
+ ibus_lookup_table_set_orientation(active_engine_->table,
vertical ? IBUS_ORIENTATION_VERTICAL :
IBUS_ORIENTATION_HORIZONTAL);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void SetPageSize(unsigned int size) {
page_size_ = size;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetPageSize";
- ibus_lookup_table_set_page_size(engine_->table, size);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_lookup_table_set_page_size(active_engine_->table, size);
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void ClearCandidates() {
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "ClearCandidates";
- ibus_lookup_table_clear(engine_->table);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_lookup_table_clear(active_engine_->table);
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
@@ -252,9 +271,9 @@ class IBusEngineControllerImpl : public IBusEngineController {
virtual void SetCandidates(std::vector<Candidate> candidates) {
// Text with this foreground color will be treated as an annotation.
const guint kAnnotationForegroundColor = 0x888888;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetCandidates";
- ibus_lookup_table_clear(engine_->table);
+ ibus_lookup_table_clear(active_engine_->table);
for (std::vector<Candidate>::iterator ix = candidates.begin();
ix != candidates.end(); ++ix ) {
@@ -269,69 +288,264 @@ class IBusEngineControllerImpl : public IBusEngineController {
// candidate window will treat it properly.
size_t end = start + g_utf8_strlen(ix->annotation.c_str(), -1);
IBusText* ibus_text = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(candidate.c_str())));
+ ibus_text_new_from_string(candidate.c_str()));
ibus_text_append_attribute(ibus_text,
IBUS_ATTR_TYPE_FOREGROUND,
kAnnotationForegroundColor,
start,
end);
- ibus_lookup_table_append_candidate(engine_->table, ibus_text);
+ ibus_lookup_table_append_candidate(active_engine_->table, ibus_text);
} else {
IBusText* ibus_text = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(ix->value.c_str())));
- ibus_lookup_table_append_candidate(engine_->table, ibus_text);
+ ibus_text_new_from_string(ix->value.c_str()));
+ ibus_lookup_table_append_candidate(active_engine_->table, ibus_text);
}
// Add the label if it's set.
if (!ix->label.empty()) {
IBusText* ibus_label = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(ix->label.c_str())));
- ibus_lookup_table_set_label(engine_->table,
+ ibus_text_new_from_string(ix->label.c_str()));
+ ibus_lookup_table_set_label(active_engine_->table,
std::distance(candidates.begin(), ix),
ibus_label);
}
}
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void SetCandidateAuxText(const char* text) {
aux_text_ = text;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetCandidateAuxText";
IBusText* ibus_text = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(aux_text_.c_str())));
- ibus_engine_update_auxiliary_text(IBUS_ENGINE(engine_), ibus_text,
+ ibus_text_new_from_string(aux_text_.c_str()));
+ ibus_engine_update_auxiliary_text(IBUS_ENGINE(active_engine_), ibus_text,
aux_text_visible_);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void SetCandidateAuxTextVisible(bool visible) {
aux_text_visible_ = visible;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetCandidateAuxTextVisible";
IBusText* ibus_text = static_cast<IBusText*>(
- g_object_ref_sink(ibus_text_new_from_string(aux_text_.c_str())));
- ibus_engine_update_auxiliary_text(IBUS_ENGINE(engine_), ibus_text,
+ ibus_text_new_from_string(aux_text_.c_str()));
+ ibus_engine_update_auxiliary_text(IBUS_ENGINE(active_engine_), ibus_text,
aux_text_visible_);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
virtual void SetCursorPosition(unsigned int position) {
cursor_position_ = position;
- if (engine_) {
+ if (active_engine_) {
VLOG(1) << "SetCursorPosition";
- ibus_lookup_table_set_cursor_pos(engine_->table, position);
- ibus_engine_update_lookup_table(IBUS_ENGINE(engine_), engine_->table,
+ ibus_lookup_table_set_cursor_pos(active_engine_->table, position);
+ ibus_engine_update_lookup_table(IBUS_ENGINE(active_engine_),
+ active_engine_->table,
table_visible_);
}
}
+ virtual bool RegisterProperties(
+ const std::vector<EngineProperty*>& properties) {
+ VLOG(1) << "RegisterProperties";
+ ClearProperties();
+ CopyProperties(properties, &properties_);
+
+ if (active_engine_) {
+ if (!SetProperties()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void ClearProperties() {
+ STLDeleteContainerPointers(properties_.begin(), properties_.end());
+ properties_.clear();
+ property_map_.clear();
+ }
+
+ virtual bool UpdateProperties(
+ const std::vector<EngineProperty*>& properties) {
+ VLOG(1) << "UpdateProperties";
+ return UpdatePropertyList(properties);
+ }
+
+ void CopyProperties(const std::vector<EngineProperty*>& properties,
+ std::vector<EngineProperty*>* dest) {
+ for (std::vector<EngineProperty*>::const_iterator property =
+ properties.begin(); property != properties.end(); ++property) {
+ if (property_map_.find((*property)->key) != property_map_.end()) {
+ LOG(ERROR) << "Property collision on name: " << (*property)->key;
+ return;
+ }
+
+ EngineProperty* new_property = new EngineProperty;
+ dest->push_back(new_property);
+ property_map_[(*property)->key] = new_property;
+
+ new_property->key = (*property)->key;
+ new_property->label = (*property)->label;
+ new_property->tooltip = (*property)->tooltip;
+ new_property->sensitive = (*property)->sensitive;
+ new_property->visible = (*property)->visible;
+ new_property->type = (*property)->type;
+ new_property->checked = (*property)->checked;
+
+ CopyProperties((*property)->children, &(new_property->children));
+ }
+ }
+
+ IBusPropList *MakePropertyList(
+ const std::vector<EngineProperty*>& properties) {
+ IBusPropList *prop_list = ibus_prop_list_new();
+ for (std::vector<EngineProperty*>::const_iterator property =
+ properties.begin(); property != properties.end(); ++property) {
+ IBusPropList *children = NULL;
+ if (!(*property)->children.empty()) {
+ children = MakePropertyList((*property)->children);
+ }
+
+ IBusPropType type = PROP_TYPE_NORMAL;
+ switch ((*property)->type) {
+ case PROPERTY_TYPE_NORMAL:
+ type = PROP_TYPE_NORMAL;
+ break;
+ case PROPERTY_TYPE_TOGGLE:
+ type = PROP_TYPE_TOGGLE;
+ break;
+ case PROPERTY_TYPE_RADIO:
+ type = PROP_TYPE_RADIO;
+ break;
+ case PROPERTY_TYPE_SEPARATOR:
+ type = PROP_TYPE_SEPARATOR;
+ break;
+ case PROPERTY_TYPE_MENU:
+ type = PROP_TYPE_MENU;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ IBusPropState state = (*property)->checked ? PROP_STATE_CHECKED :
+ PROP_STATE_UNCHECKED;
+
+ IBusProperty *ibus_property =
+ ibus_property_new((*property)->key.c_str(),
+ type,
+ static_cast<IBusText*>(
+ ibus_text_new_from_string(
+ (*property)->label.c_str())),
+ NULL,
+ static_cast<IBusText*>(
+ ibus_text_new_from_string(
+ (*property)->tooltip.c_str())),
+ (*property)->sensitive,
+ (*property)->visible,
+ state,
+ children);
+
+ ibus_prop_list_append(prop_list, ibus_property);
+ }
+ return prop_list;
+ }
+
+ bool SetProperties() {
+ IBusPropList *prop_list = MakePropertyList(properties_);
+ ibus_engine_register_properties(IBUS_ENGINE(active_engine_), prop_list);
+ return true;
+ }
+
+ bool UpdatePropertyList(const std::vector<EngineProperty*>& properties) {
+ for (std::vector<EngineProperty*>::const_iterator property =
+ properties.begin(); property != properties.end(); ++property) {
+ std::map<std::string, EngineProperty*>::iterator cur_property =
+ property_map_.find((*property)->key);
+ if (cur_property == property_map_.end()) {
+ LOG(ERROR) << "Missing property: " << (*property)->key;
+ return false;
+ }
+
+ if ((*property)->modified & PROPERTY_MODIFIED_LABEL) {
+ cur_property->second->label = (*property)->label;
+ }
+ if ((*property)->modified & PROPERTY_MODIFIED_TOOLTIP) {
+ cur_property->second->tooltip = (*property)->tooltip;
+ }
+ if ((*property)->modified & PROPERTY_MODIFIED_SENSITIVE) {
+ cur_property->second->sensitive = (*property)->sensitive;
+ }
+ if ((*property)->modified & PROPERTY_MODIFIED_VISIBLE) {
+ cur_property->second->visible = (*property)->visible;
+ }
+ if ((*property)->modified & PROPERTY_MODIFIED_TYPE) {
+ cur_property->second->type = (*property)->type;
+ }
+ if ((*property)->modified & PROPERTY_MODIFIED_CHECKED) {
+ cur_property->second->checked = (*property)->checked;
+ }
+
+ if (active_engine_) {
+ IBusPropType type = PROP_TYPE_NORMAL;
+ switch (cur_property->second->type) {
+ case PROPERTY_TYPE_NORMAL:
+ type = PROP_TYPE_NORMAL;
+ break;
+ case PROPERTY_TYPE_TOGGLE:
+ type = PROP_TYPE_TOGGLE;
+ break;
+ case PROPERTY_TYPE_RADIO:
+ type = PROP_TYPE_RADIO;
+ break;
+ case PROPERTY_TYPE_SEPARATOR:
+ type = PROP_TYPE_SEPARATOR;
+ break;
+ case PROPERTY_TYPE_MENU:
+ type = PROP_TYPE_MENU;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ IBusPropState state = cur_property->second->checked ?
+ PROP_STATE_CHECKED : PROP_STATE_UNCHECKED;
+
+ IBusProperty *ibus_property =
+ ibus_property_new(cur_property->second->key.c_str(),
+ type,
+ static_cast<IBusText*>(
+ ibus_text_new_from_string(
+ cur_property->second->label.c_str())),
+ NULL,
+ static_cast<IBusText*>(
+ ibus_text_new_from_string(
+ cur_property->second->tooltip.c_str())),
+ cur_property->second->sensitive,
+ cur_property->second->visible,
+ state,
+ NULL);
+
+ ibus_engine_update_property(IBUS_ENGINE(active_engine_), ibus_property);
+ }
+ if (!UpdatePropertyList((*property)->children)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
virtual void KeyEventDone(KeyEventHandle* key_data, bool handled) {
GDBusMethodInvocation* invocation =
reinterpret_cast<GDBusMethodInvocation*>(key_data);
@@ -506,19 +720,25 @@ class IBusEngineControllerImpl : public IBusEngineController {
static void OnEnable(IBusEngine* ibus_engine) {
VLOG(1) << "OnEnable";
IBusChromeOSEngine* engine = IBUS_CHROMEOS_ENGINE(ibus_engine);
+ engine->connection->active_engine_ = engine;
engine->connection->observer_->OnEnable();
+ engine->connection->SetProperties();
}
static void OnDisable(IBusEngine* ibus_engine) {
VLOG(1) << "OnDisable";
IBusChromeOSEngine* engine = IBUS_CHROMEOS_ENGINE(ibus_engine);
engine->connection->observer_->OnDisable();
+ if (engine->connection->active_engine_ == engine) {
+ engine->connection->active_engine_ = NULL;
+ }
}
static void OnFocusIn(IBusEngine* ibus_engine) {
VLOG(1) << "OnFocusIn";
IBusChromeOSEngine* engine = IBUS_CHROMEOS_ENGINE(ibus_engine);
engine->connection->observer_->OnFocusIn();
+ engine->connection->SetProperties();
}
static void OnFocusOut(IBusEngine* ibus_engine) {
@@ -579,7 +799,13 @@ class IBusEngineControllerImpl : public IBusEngineController {
LOG(ERROR) << "Connection never created: " << name;
return (GObject *) engine;
}
- connection->second->engine_ = engine;
+
+ connection->second->engine_instances_.insert(engine);
+
+ if (!connection->second->active_engine_) {
+ connection->second->active_engine_ = engine;
+ }
+
engine->connection = connection->second;
engine->table = ibus_lookup_table_new(connection->second->page_size_,
@@ -593,6 +819,10 @@ class IBusEngineControllerImpl : public IBusEngineController {
IBUS_ORIENTATION_HORIZONTAL);
ibus_engine_update_lookup_table(IBUS_ENGINE(engine), engine->table,
connection->second->table_visible_);
+
+
+ connection->second->SetProperties();
+
return (GObject *) engine;
}
@@ -601,7 +831,11 @@ class IBusEngineControllerImpl : public IBusEngineController {
ConnectionMap::iterator connection = g_connections_->find(name);
if (connection == g_connections_->end()) {
LOG(ERROR) << "Connection already destroyed, or never created: " << name;
- return;
+ } else {
+ connection->second->engine_instances_.erase(chromeos_engine);
+ if (connection->second->active_engine_ == chromeos_engine) {
+ connection->second->active_engine_ = NULL;
+ }
}
if (chromeos_engine->table) {
g_object_unref(chromeos_engine->table);
@@ -613,7 +847,7 @@ class IBusEngineControllerImpl : public IBusEngineController {
IBusEngineController::Observer* observer_;
IBusBus* ibus_;
- IBusChromeOSEngine* engine_;
+ IBusChromeOSEngine* active_engine_;
std::string engine_id_;
std::string engine_name_;
@@ -631,6 +865,10 @@ class IBusEngineControllerImpl : public IBusEngineController {
unsigned int cursor_position_;
std::string aux_text_;
bool aux_text_visible_;
+ std::vector<EngineProperty*> properties_;
+ std::map<std::string, EngineProperty*> property_map_;
+
+ std::set<IBusChromeOSEngine*> engine_instances_;
static ConnectionMap* g_connections_;
};
diff --git a/chrome/browser/chromeos/input_method/ibus_engine_controller.h b/chrome/browser/chromeos/input_method/ibus_engine_controller.h
index b7f741b..c8e8dd0 100644
--- a/chrome/browser/chromeos/input_method/ibus_engine_controller.h
+++ b/chrome/browser/chromeos/input_method/ibus_engine_controller.h
@@ -57,6 +57,31 @@ class IBusEngineController {
std::string annotation;
};
+ enum {
+ PROPERTY_MODIFIED_LABEL = 0x0001,
+ PROPERTY_MODIFIED_TOOLTIP = 0x0002,
+ PROPERTY_MODIFIED_SENSITIVE = 0x0004,
+ PROPERTY_MODIFIED_VISIBLE = 0x0008,
+ PROPERTY_MODIFIED_TYPE = 0x0010,
+ PROPERTY_MODIFIED_CHECKED = 0x0020,
+ };
+
+ struct EngineProperty {
+ EngineProperty();
+ virtual ~EngineProperty();
+
+ std::string key;
+ std::string label;
+ std::string tooltip;
+ bool sensitive;
+ bool visible;
+ int type;
+ bool checked;
+
+ unsigned int modified;
+ std::vector<EngineProperty*> children;
+ };
+
// Constants for the button parameter of OnCandidateClicked
enum {
MOUSE_BUTTON_1_MASK = 0x01,
@@ -73,6 +98,15 @@ class IBusEngineController {
UNDERLINE_ERROR
};
+ // Constants for RegisterProperties and UpdateProperties
+ enum {
+ PROPERTY_TYPE_NORMAL,
+ PROPERTY_TYPE_TOGGLE,
+ PROPERTY_TYPE_RADIO,
+ PROPERTY_TYPE_SEPARATOR,
+ PROPERTY_TYPE_MENU
+ };
+
static IBusEngineController* Create(Observer* observer,
const char* engine_id,
const char* engine_name,
@@ -118,6 +152,14 @@ class IBusEngineController {
// Set the posistion of the cursor in the candidate window.
virtual void SetCursorPosition(unsigned int position) = 0;
+ // Set the properties that ibus will display in the language bar.
+ virtual bool RegisterProperties(
+ const std::vector<EngineProperty*>& properties) = 0;
+
+ // Update the attributes of the listed properties.
+ virtual bool UpdateProperties(
+ const std::vector<EngineProperty*>& properties) = 0;
+
// Inform the engine that a key event has been processed.
virtual void KeyEventDone(KeyEventHandle* key_data, bool handled) = 0;
};
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index 0f70c95..5bbe0fc 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -21,7 +21,10 @@ const char* kErrorNotActive = "IME is not active";
const char* kErrorWrongContext = "Context is not active";
const char* kCandidateNotFound = "Candidate not found";
-InputMethodEngine::KeyboardEvent::KeyboardEvent() {
+InputMethodEngine::KeyboardEvent::KeyboardEvent()
+ : alt_key(false),
+ ctrl_key(false),
+ shift_key(false) {
}
InputMethodEngine::KeyboardEvent::~KeyboardEvent() {
@@ -84,8 +87,8 @@ class InputMethodEngineImpl
std::string* error);
virtual bool SetCursorPosition(int context_id, int candidate_id,
std::string* error);
- virtual void SetMenuItems(const std::vector<MenuItem>& items);
- virtual void UpdateMenuItems(const std::vector<MenuItem>& items);
+ virtual bool SetMenuItems(const std::vector<MenuItem>& items);
+ virtual bool UpdateMenuItems(const std::vector<MenuItem>& items);
virtual bool IsActive() const {
return active_;
}
@@ -105,6 +108,10 @@ class InputMethodEngineImpl
virtual void OnCandidateClicked(unsigned int index, unsigned int button,
unsigned int state);
private:
+ bool MenuItemToProperty(
+ const MenuItem& item,
+ input_method::IBusEngineController::EngineProperty* property);
+
// Pointer to the object recieving events for this IME.
InputMethodEngine::Observer* observer_;
@@ -130,30 +137,9 @@ class InputMethodEngineImpl
std::vector<int> candidate_ids_;
// Mapping of candidate id to index.
- std::map<int, int> candidate_indexs_;
+ std::map<int, int> candidate_indexes_;
};
-InputMethodEngine* InputMethodEngine::CreateEngine(
- InputMethodEngine::Observer* observer,
- const char* engine_name,
- const char* extension_id,
- const char* engine_id,
- const char* description,
- const char* language,
- const std::vector<std::string>& layouts,
- KeyboardEvent& shortcut_key,
- std::string* error) {
- InputMethodEngineImpl* new_engine = new InputMethodEngineImpl();
- if (!new_engine->Init(observer, engine_name, extension_id, engine_id,
- description, language, layouts, shortcut_key, error)) {
- LOG(ERROR) << "Init() failed.";
- delete new_engine;
- new_engine = NULL;
- }
-
- return new_engine;
-}
-
bool InputMethodEngineImpl::Init(InputMethodEngine::Observer* observer,
const char* engine_name,
const char* extension_id,
@@ -323,7 +309,7 @@ bool InputMethodEngineImpl::SetCandidates(
ibus_candidates.back().annotation = ix->annotation;
// Store a mapping from the user defined ID to the candidate index.
- candidate_indexs_[ix->id] = candidate_ids_.size();
+ candidate_indexes_[ix->id] = candidate_ids_.size();
candidate_ids_.push_back(ix->id);
}
connection_->SetCandidates(ibus_candidates);
@@ -342,8 +328,8 @@ bool InputMethodEngineImpl::SetCursorPosition(int context_id, int candidate_id,
}
std::map<int, int>::const_iterator position =
- candidate_indexs_.find(candidate_id);
- if (position == candidate_indexs_.end()) {
+ candidate_indexes_.find(candidate_id);
+ if (position == candidate_indexes_.end()) {
*error = kCandidateNotFound;
return false;
}
@@ -352,13 +338,108 @@ bool InputMethodEngineImpl::SetCursorPosition(int context_id, int candidate_id,
return true;
}
-void InputMethodEngineImpl::SetMenuItems(const std::vector<MenuItem>& items) {
- // TODO(zork): Implement this function
+bool InputMethodEngineImpl::SetMenuItems(const std::vector<MenuItem>& items) {
+ std::vector<input_method::IBusEngineController::EngineProperty*> properties;
+
+ for (std::vector<MenuItem>::const_iterator item = items.begin();
+ item != items.end(); ++item) {
+ input_method::IBusEngineController::EngineProperty* property =
+ new input_method::IBusEngineController::EngineProperty;
+ if (!MenuItemToProperty(*item, property)) {
+ delete property;
+ LOG(ERROR) << "Bad menu item";
+ return false;
+ }
+ properties.push_back(property);
+ }
+ return connection_->RegisterProperties(properties);
+}
+
+bool InputMethodEngineImpl::MenuItemToProperty(
+ const MenuItem& item,
+ input_method::IBusEngineController::EngineProperty* property) {
+ property->key = item.id;
+ property->label = item.label;
+ property->visible = item.visible;
+ property->sensitive = item.enabled;
+ property->checked = item.checked;
+
+ if (!item.children.empty()) {
+ property->type = input_method::IBusEngineController::PROPERTY_TYPE_MENU;
+ } else {
+ switch (item.style) {
+ case MENU_ITEM_STYLE_NONE:
+ property->type =
+ input_method::IBusEngineController::PROPERTY_TYPE_NORMAL;
+ break;
+ case MENU_ITEM_STYLE_CHECK:
+ property->type =
+ input_method::IBusEngineController::PROPERTY_TYPE_TOGGLE;
+ break;
+ case MENU_ITEM_STYLE_RADIO:
+ property->type =
+ input_method::IBusEngineController::PROPERTY_TYPE_RADIO;
+ break;
+ case MENU_ITEM_STYLE_SEPARATOR:
+ property->type =
+ input_method::IBusEngineController::PROPERTY_TYPE_SEPARATOR;
+ break;
+ }
+ }
+
+ property->modified = 0;
+ if (item.modified & MENU_ITEM_MODIFIED_LABEL) {
+ property->modified |=
+ input_method::IBusEngineController::PROPERTY_MODIFIED_LABEL;
+ }
+ if (item.modified & MENU_ITEM_MODIFIED_STYLE) {
+ property->modified |=
+ input_method::IBusEngineController::PROPERTY_MODIFIED_TYPE;
+ }
+ if (item.modified & MENU_ITEM_MODIFIED_VISIBLE) {
+ property->modified |=
+ input_method::IBusEngineController::PROPERTY_MODIFIED_VISIBLE;
+ }
+ if (item.modified & MENU_ITEM_MODIFIED_ENABLED) {
+ property->modified |=
+ input_method::IBusEngineController::PROPERTY_MODIFIED_SENSITIVE;
+ }
+ if (item.modified & MENU_ITEM_MODIFIED_CHECKED) {
+ property->modified |=
+ input_method::IBusEngineController::PROPERTY_MODIFIED_CHECKED;
+ }
+
+ for (std::vector<MenuItem>::const_iterator child = item.children.begin();
+ child != item.children.end(); ++child) {
+ input_method::IBusEngineController::EngineProperty* new_property =
+ new input_method::IBusEngineController::EngineProperty;
+ if (!MenuItemToProperty(*child, new_property)) {
+ delete new_property;
+ LOG(ERROR) << "Bad menu item child";
+ return false;
+ }
+ property->children.push_back(new_property);
+ }
+
+ return true;
}
-void InputMethodEngineImpl::UpdateMenuItems(
+bool InputMethodEngineImpl::UpdateMenuItems(
const std::vector<MenuItem>& items) {
- // TODO(zork): Implement this function
+ std::vector<input_method::IBusEngineController::EngineProperty*> properties;
+
+ for (std::vector<MenuItem>::const_iterator item = items.begin();
+ item != items.end(); ++item) {
+ input_method::IBusEngineController::EngineProperty* new_property =
+ new input_method::IBusEngineController::EngineProperty();
+ if (!MenuItemToProperty(*item, new_property)) {
+ LOG(ERROR) << "Bad menu item";
+ delete new_property;
+ return false;
+ }
+ properties.push_back(new_property);
+ }
+ return connection_->UpdateProperties(properties);
}
void InputMethodEngineImpl::KeyEventDone(input_method::KeyEventHandle* key_data,
@@ -436,4 +517,147 @@ void InputMethodEngineImpl::OnCandidateClicked(unsigned int index,
observer_->OnCandidateClicked(engine_id_, candidate_ids_.at(index), button);
}
+class InputMethodEngineStub : public InputMethodEngine {
+ public:
+ InputMethodEngineStub()
+ : observer_(NULL), active_(false), next_context_id_(1),
+ context_id_(-1) {}
+
+ ~InputMethodEngineStub() {
+ }
+
+ bool Init(InputMethodEngine::Observer* observer,
+ const char* engine_name,
+ const char* extension_id,
+ const char* engine_id,
+ const char* description,
+ const char* language,
+ const std::vector<std::string>& layouts,
+ KeyboardEvent& shortcut_key,
+ std::string* error) {
+ VLOG(0) << "Init";
+ return true;
+ }
+
+ virtual bool SetComposition(int context_id,
+ const char* text, int selection_start,
+ int selection_end,
+ const std::vector<SegmentInfo>& segments,
+ std::string* error) {
+ VLOG(0) << "SetComposition";
+ return true;
+ }
+
+ virtual bool ClearComposition(int context_id, std::string* error) {
+ VLOG(0) << "ClearComposition";
+ return true;
+ }
+
+ virtual bool CommitText(int context_id,
+ const char* text, std::string* error) {
+ VLOG(0) << "CommitText";
+ return true;
+ }
+
+ virtual bool SetCandidateWindowVisible(bool visible, std::string* error) {
+ VLOG(0) << "SetCandidateWindowVisible";
+ return true;
+ }
+
+ virtual void SetCandidateWindowCursorVisible(bool visible) {
+ VLOG(0) << "SetCandidateWindowCursorVisible";
+ }
+
+ virtual void SetCandidateWindowVertical(bool vertical) {
+ VLOG(0) << "SetCandidateWindowVertical";
+ }
+
+ virtual void SetCandidateWindowPageSize(int size) {
+ VLOG(0) << "SetCandidateWindowPageSize";
+ }
+
+ virtual void SetCandidateWindowAuxText(const char* text) {
+ VLOG(0) << "SetCandidateWindowAuxText";
+ }
+
+ virtual void SetCandidateWindowAuxTextVisible(bool visible) {
+ VLOG(0) << "SetCandidateWindowAuxTextVisible";
+ }
+
+ virtual bool SetCandidates(int context_id,
+ const std::vector<Candidate>& candidates,
+ std::string* error) {
+ VLOG(0) << "SetCandidates";
+ return true;
+ }
+
+ virtual bool SetCursorPosition(int context_id, int candidate_id,
+ std::string* error) {
+ VLOG(0) << "SetCursorPosition";
+ return true;
+ }
+
+ virtual bool SetMenuItems(const std::vector<MenuItem>& items) {
+ VLOG(0) << "SetMenuItems";
+ return true;
+ }
+
+ virtual bool UpdateMenuItems(const std::vector<MenuItem>& items) {
+ VLOG(0) << "UpdateMenuItems";
+ return true;
+ }
+
+ virtual bool IsActive() const {
+ VLOG(0) << "IsActive";
+ return active_;
+ }
+
+ virtual void KeyEventDone(input_method::KeyEventHandle* key_data,
+ bool handled) {
+ }
+
+ private:
+ // Pointer to the object recieving events for this IME.
+ InputMethodEngine::Observer* observer_;
+
+ // True when this IME is active, false if deactive.
+ bool active_;
+
+ // Next id that will be assigned to a context.
+ int next_context_id_;
+
+ // ID that is used for the current input context. False if there is no focus.
+ int context_id_;
+
+ // User specified id of this IME.
+ std::string engine_id_;
+};
+
+InputMethodEngine* InputMethodEngine::CreateEngine(
+ InputMethodEngine::Observer* observer,
+ const char* engine_name,
+ const char* extension_id,
+ const char* engine_id,
+ const char* description,
+ const char* language,
+ const std::vector<std::string>& layouts,
+ KeyboardEvent& shortcut_key,
+ std::string* error) {
+
+#if defined(HAVE_IBUS)
+ InputMethodEngineImpl* new_engine = new InputMethodEngineImpl();
+#else
+ InputMethodEngineStub* new_engine = new InputMethodEngineStub();
+#endif
+
+ if (!new_engine->Init(observer, engine_name, extension_id, engine_id,
+ description, language, layouts, shortcut_key, error)) {
+ LOG(ERROR) << "Init() failed.";
+ delete new_engine;
+ new_engine = NULL;
+ }
+
+ return new_engine;
+}
+
} // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h
index 3cf82dd..64bb61b 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine.h
@@ -33,6 +33,16 @@ class InputMethodEngine {
bool shift_key;
};
+ enum {
+ MENU_ITEM_MODIFIED_LABEL = 0x0001,
+ MENU_ITEM_MODIFIED_STYLE = 0x0002,
+ MENU_ITEM_MODIFIED_VISIBLE = 0x0004,
+ MENU_ITEM_MODIFIED_ENABLED = 0x0008,
+ MENU_ITEM_MODIFIED_CHECKED = 0x0010,
+ MENU_ITEM_MODIFIED_ICON = 0x0020,
+ MENU_ITEM_MODIFIED_SHORTCUT_KEY = 0x0040,
+ };
+
struct MenuItem {
MenuItem();
virtual ~MenuItem();
@@ -45,6 +55,8 @@ class InputMethodEngine {
bool checked;
std::string icon;
KeyboardEvent shortcut_key;
+
+ unsigned int modified;
std::vector<MenuItem> children;
};
@@ -169,10 +181,10 @@ class InputMethodEngine {
// Set the list of items that appears in the language menu when this IME is
// active.
- virtual void SetMenuItems(const std::vector<MenuItem>& items) = 0;
+ virtual bool SetMenuItems(const std::vector<MenuItem>& items) = 0;
// Update the state of the menu items.
- virtual void UpdateMenuItems(const std::vector<MenuItem>& items) = 0;
+ virtual bool UpdateMenuItems(const std::vector<MenuItem>& items) = 0;
// Returns true if this IME is active, false if not.
virtual bool IsActive() const = 0;
diff --git a/chrome/browser/extensions/extension_input_ime_api.cc b/chrome/browser/extensions/extension_input_ime_api.cc
index 13e59b5..098a894 100644
--- a/chrome/browser/extensions/extension_input_ime_api.cc
+++ b/chrome/browser/extensions/extension_input_ime_api.cc
@@ -14,6 +14,157 @@
namespace keys = extension_input_module_constants;
+namespace {
+
+const char kStyleNone[] = "none";
+const char kStyleCheck[] = "check";
+const char kStyleRadio[] = "radio";
+const char kStyleSeparator[] = "separator";
+
+const char kErrorEngineNotAvailable[] = "Engine is not available";
+const char kErrorBadCandidateList[] = "Invalid candidate list provided";
+const char kErrorSetMenuItemsFail[] = "Could not create menu Items";
+const char kErrorUpdateMenuItemsFail[] = "Could not update menu Items";
+
+bool ReadMenuItems(
+ ListValue* menu_items,
+ std::vector<chromeos::InputMethodEngine::MenuItem>* output) {
+ for (size_t i = 0; i < menu_items->GetSize(); ++i) {
+ DictionaryValue* item_dict;
+ if (!menu_items->GetDictionary(i, &item_dict)) {
+ return false;
+ }
+
+ std::string id;
+ std::string label;
+ int style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_NONE;
+ bool visible = true;
+ bool enabled = true;
+ bool checked = false;
+ std::string icon;
+ chromeos::InputMethodEngine::KeyboardEvent shortcut_key;
+
+ unsigned int modified = 0;
+
+ if (!item_dict->GetString(keys::kIdKey, &id)) {
+ return false;
+ }
+
+ if (item_dict->HasKey(keys::kLabelKey)) {
+ if (!item_dict->GetString(keys::kLabelKey, &label)) {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_LABEL;
+ }
+ if (item_dict->HasKey(keys::kStyleKey)) {
+ std::string style_string;
+ if (!item_dict->GetString(keys::kStyleKey, &style_string)) {
+ return false;
+ }
+
+ if (style_string == kStyleNone) {
+ style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_NONE;
+ } else if (style_string == kStyleCheck) {
+ style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_CHECK;
+ } else if (style_string == kStyleRadio) {
+ style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_RADIO;
+ } else if (style_string == kStyleSeparator) {
+ style = chromeos::InputMethodEngine::MENU_ITEM_STYLE_SEPARATOR;
+ } else {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_STYLE;
+ }
+
+ if (item_dict->HasKey(keys::kVisibleKey)) {
+ if (!item_dict->GetBoolean(keys::kVisibleKey, &visible)) {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_VISIBLE;
+ }
+
+ if (item_dict->HasKey(keys::kCheckedKey)) {
+ if (!item_dict->GetBoolean(keys::kCheckedKey, &checked)) {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_CHECKED;
+ }
+
+ if (item_dict->HasKey(keys::kEnabledKey)) {
+ if (!item_dict->GetBoolean(keys::kEnabledKey, &enabled)) {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_ENABLED;
+ }
+
+ if (item_dict->HasKey(keys::kIconKey)) {
+ if (!item_dict->GetString(keys::kIconKey, &icon)) {
+ return false;
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_ICON;
+ }
+
+ if (item_dict->HasKey(keys::kShortcutKey)) {
+ DictionaryValue* shortcut_dict;
+ if (!item_dict->GetDictionary(keys::kShortcutKey, &shortcut_dict)) {
+ return false;
+ }
+
+ if (!shortcut_dict->GetString(keys::kKeyKey, &(shortcut_key.key))) {
+ return false;
+ }
+
+ if (shortcut_dict->HasKey(keys::kAltKeyKey)) {
+ if (!item_dict->GetBoolean(keys::kAltKeyKey, &(shortcut_key.alt_key))) {
+ return false;
+ }
+ }
+
+ if (shortcut_dict->HasKey(keys::kCtrlKeyKey)) {
+ if (!shortcut_dict->GetBoolean(keys::kCtrlKeyKey,
+ &(shortcut_key.ctrl_key))) {
+ return false;
+ }
+ }
+
+ if (shortcut_dict->HasKey(keys::kShiftKeyKey)) {
+ if (!shortcut_dict->GetBoolean(keys::kShiftKeyKey,
+ &(shortcut_key.shift_key))) {
+ return false;
+ }
+ }
+ modified |= chromeos::InputMethodEngine::MENU_ITEM_MODIFIED_SHORTCUT_KEY;
+ }
+
+ output->push_back(chromeos::InputMethodEngine::MenuItem());
+ output->back().id = id;
+ output->back().label = label;
+ output->back().style = style;
+ output->back().visible = visible;
+ output->back().enabled = enabled;
+ output->back().checked = checked;
+ output->back().icon = icon;
+ output->back().shortcut_key = shortcut_key;
+
+ output->back().modified = modified;
+
+ if (item_dict->HasKey(keys::kItemsKey)) {
+ ListValue* sub_list;
+ if (!item_dict->GetList(keys::kItemsKey, &sub_list)) {
+ return false;
+ }
+
+ if (!ReadMenuItems(sub_list, &(output->back().children))) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+}
+
namespace events {
const char kOnActivate[] = "experimental.input.onActivate";
@@ -343,9 +494,7 @@ bool SetCompositionFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->
GetActiveEngine(extension_id());
if (!engine) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
+ result_.reset(Value::CreateBooleanValue(false));
return true;
}
@@ -374,6 +523,7 @@ bool SetCompositionFunction::RunImpl() {
}
if (args->HasKey(keys::kSegmentsKey)) {
+ // TODO: Handle segments
ListValue* segment_list;
EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kSegmentsKey,
&segment_list));
@@ -398,20 +548,13 @@ bool SetCompositionFunction::RunImpl() {
}
}
- std::string error;
-
if (engine->SetComposition(context_id, text.c_str(), selection_start,
- selection_end, segments, &error)) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
- return true;
+ selection_end, segments, &error_)) {
+ result_.reset(Value::CreateBooleanValue(true));
} else {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
}
+ return true;
}
bool ClearCompositionFunction::RunImpl() {
@@ -419,7 +562,8 @@ bool ClearCompositionFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->
GetActiveEngine(extension_id());
if (!engine) {
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
DictionaryValue* args;
@@ -429,18 +573,12 @@ bool ClearCompositionFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kContextIdKey,
&context_id));
- std::string error;
- if (engine->ClearComposition(context_id, &error)) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
- return true;
+ if (engine->ClearComposition(context_id, &error_)) {
+ result_.reset(Value::CreateBooleanValue(true));
} else {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
}
+ return true;
}
bool CommitTextFunction::RunImpl() {
@@ -449,7 +587,8 @@ bool CommitTextFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->
GetActiveEngine(extension_id());
if (!engine) {
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
DictionaryValue* args;
@@ -461,18 +600,12 @@ bool CommitTextFunction::RunImpl() {
&context_id));
EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kTextKey, &text));
- std::string error;
- if (engine->CommitText(context_id, text.c_str(), &error)) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
- return true;
+ if (engine->CommitText(context_id, text.c_str(), &error_)) {
+ result_.reset(Value::CreateBooleanValue(true));
} else {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
}
+ return true;
}
bool SetCandidateWindowPropertiesFunction::RunImpl() {
@@ -486,21 +619,21 @@ bool SetCandidateWindowPropertiesFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(),
engine_id);
if (!engine) {
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
DictionaryValue* properties;
EXTENSION_FUNCTION_VALIDATE(args->GetDictionary(keys::kPropertiesKey,
&properties));
- std::string error;
-
if (properties->HasKey(keys::kVisibleKey)) {
bool visible;
EXTENSION_FUNCTION_VALIDATE(properties->GetBoolean(keys::kVisibleKey,
&visible));
- if (!engine->SetCandidateWindowVisible(visible, &error)) {
- return false;
+ if (!engine->SetCandidateWindowVisible(visible, &error_)) {
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
}
@@ -540,9 +673,7 @@ bool SetCandidateWindowPropertiesFunction::RunImpl() {
engine->SetCandidateWindowAuxTextVisible(visible);
}
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
+ result_.reset(Value::CreateBooleanValue(true));
return true;
}
@@ -585,6 +716,7 @@ bool SetCandidatesFunction::ReadCandidates(
EXTENSION_FUNCTION_VALIDATE(candidate_dict->GetList(keys::kCandidatesKey,
&sub_list));
if (!ReadCandidates(sub_list, &(output->back().candidates))) {
+ error_ = kErrorBadCandidateList;
return false;
}
}
@@ -598,7 +730,8 @@ bool SetCandidatesFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->
GetActiveEngine(extension_id());
if (!engine) {
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
DictionaryValue* args;
@@ -614,21 +747,17 @@ bool SetCandidatesFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kCandidatesKey,
&candidate_list));
if (!ReadCandidates(candidate_list, &candidates)) {
+ error_ = kErrorBadCandidateList;
return false;
}
std::string error;
- if (engine->SetCandidates(context_id, candidates, &error)) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
- return true;
+ if (engine->SetCandidates(context_id, candidates, &error_)) {
+ result_.reset(Value::CreateBooleanValue(true));
} else {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
}
+ return true;
}
bool SetCursorPositionFunction::RunImpl() {
@@ -636,7 +765,8 @@ bool SetCursorPositionFunction::RunImpl() {
ExtensionInputImeEventRouter::GetInstance()->
GetActiveEngine(extension_id());
if (!engine) {
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
+ return true;
}
DictionaryValue* args;
@@ -649,28 +779,65 @@ bool SetCursorPositionFunction::RunImpl() {
EXTENSION_FUNCTION_VALIDATE(args->GetInteger(keys::kCandidateIdKey,
&candidate_id));
- std::string error;
- if (engine->SetCursorPosition(context_id, candidate_id, &error)) {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(true));
- }
- return true;
+ if (engine->SetCursorPosition(context_id, candidate_id, &error_)) {
+ result_.reset(Value::CreateBooleanValue(true));
} else {
- if (has_callback()) {
- result_.reset(Value::CreateBooleanValue(false));
- }
- return false;
+ result_.reset(Value::CreateBooleanValue(false));
}
return true;
}
bool SetMenuItemsFunction::RunImpl() {
- // TODO
+ DictionaryValue* args;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
+
+ std::string engine_id;
+ EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kEngineIdKey, &engine_id));
+
+ chromeos::InputMethodEngine* engine =
+ ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(),
+ engine_id);
+ if (!engine) {
+ error_ = kErrorEngineNotAvailable;
+ return false;
+ }
+
+ ListValue* items;
+ EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items));
+
+ std::vector<chromeos::InputMethodEngine::MenuItem> menu_items;
+ EXTENSION_FUNCTION_VALIDATE(ReadMenuItems(items, &menu_items));
+
+ if (!engine->SetMenuItems(menu_items)) {
+ error_ = kErrorSetMenuItemsFail;
+ }
return true;
}
bool UpdateMenuItemsFunction::RunImpl() {
- // TODO
+ DictionaryValue* args;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
+
+ std::string engine_id;
+ EXTENSION_FUNCTION_VALIDATE(args->GetString(keys::kEngineIdKey, &engine_id));
+
+ chromeos::InputMethodEngine* engine =
+ ExtensionInputImeEventRouter::GetInstance()->GetEngine(extension_id(),
+ engine_id);
+ if (!engine) {
+ error_ = kErrorEngineNotAvailable;
+ return false;
+ }
+
+ ListValue* items;
+ EXTENSION_FUNCTION_VALIDATE(args->GetList(keys::kItemsKey, &items));
+
+ std::vector<chromeos::InputMethodEngine::MenuItem> menu_items;
+ EXTENSION_FUNCTION_VALIDATE(ReadMenuItems(items, &menu_items));
+
+ if (!engine->UpdateMenuItems(menu_items)) {
+ error_ = kErrorUpdateMenuItemsFail;
+ }
return true;
}
diff --git a/chrome/browser/extensions/extension_input_ime_api.h b/chrome/browser/extensions/extension_input_ime_api.h
index b1ebeaced..063ba38 100644
--- a/chrome/browser/extensions/extension_input_ime_api.h
+++ b/chrome/browser/extensions/extension_input_ime_api.h
@@ -110,14 +110,14 @@ class SetCursorPositionFunction : public AsyncExtensionFunction {
"experimental.input.setCursorPosition");
};
-class SetMenuItemsFunction : public AsyncExtensionFunction {
+class SetMenuItemsFunction : public SyncExtensionFunction {
public:
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME(
"experimental.input.setMenuItems");
};
-class UpdateMenuItemsFunction : public AsyncExtensionFunction {
+class UpdateMenuItemsFunction : public SyncExtensionFunction {
public:
virtual bool RunImpl();
DECLARE_EXTENSION_FUNCTION_NAME(
diff --git a/chrome/browser/extensions/extension_input_ime_apitest.cc b/chrome/browser/extensions/extension_input_ime_apitest.cc
new file mode 100644
index 0000000..1c4bd77
--- /dev/null
+++ b/chrome/browser/extensions/extension_input_ime_apitest.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_test_api.h"
+#include "chrome/common/chrome_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(ExtensionApiTest, InputImeApiBasic) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
+ ASSERT_TRUE(RunExtensionTest("input_ime")) << message_;
+}
+#endif
diff --git a/chrome/browser/extensions/extension_input_module_constants.cc b/chrome/browser/extensions/extension_input_module_constants.cc
index 18ce4b2..c6bbbf8 100644
--- a/chrome/browser/extensions/extension_input_module_constants.cc
+++ b/chrome/browser/extensions/extension_input_module_constants.cc
@@ -6,23 +6,33 @@
namespace extension_input_module_constants {
+const char kAltKeyKey[] = "altKey";
const char kAnnotationKey[] = "annotation";
const char kAuxiliaryTextKey[] = "auxiliaryText";
const char kAuxiliaryTextVisibleKey[] = "auxiliaryTextVisible";
const char kCandidateIdKey[] = "candidateID";
const char kCandidateKey[] = "candidate";
const char kCandidatesKey[] = "candidates";
+const char kCheckedKey[] = "checked";
const char kContextIdKey[] = "contextID";
+const char kCtrlKeyKey[] = "ctrlKey";
const char kCursorVisibleKey[] = "cursorVisible";
+const char kEnabledKey[] = "enabled";
const char kEndKey[] = "end";
const char kEngineIdKey[] = "engineID";
+const char kIconKey[] = "icon";
const char kIdKey[] = "id";
+const char kItemsKey[] = "items";
+const char kKeyKey[] = "key";
const char kLabelKey[] = "label";
const char kPageSizeKey[] = "pageSize";
+const char kParentIdKey[] = "parentId";
const char kPropertiesKey[] = "properties";
const char kSegmentsKey[] = "segments";
const char kSelectionEndKey[] = "selectionEnd";
const char kSelectionStartKey[] = "selectionStart";
+const char kShiftKeyKey[] = "shiftKey";
+const char kShortcutKey[] = "shortcut";
const char kStartKey[] = "start";
const char kStyleDoubleUnderline[] = "doubleUnderline";
const char kStyleKey[] = "style";
diff --git a/chrome/browser/extensions/extension_input_module_constants.h b/chrome/browser/extensions/extension_input_module_constants.h
index 784a67c..9cf8a1b 100644
--- a/chrome/browser/extensions/extension_input_module_constants.h
+++ b/chrome/browser/extensions/extension_input_module_constants.h
@@ -11,23 +11,33 @@
namespace extension_input_module_constants {
// Keys used in serializing input data & events.
+extern const char kAltKeyKey[];
extern const char kAnnotationKey[];
extern const char kAuxiliaryTextKey[];
extern const char kAuxiliaryTextVisibleKey[];
extern const char kCandidateIdKey[];
extern const char kCandidateKey[];
extern const char kCandidatesKey[];
+extern const char kCheckedKey[];
extern const char kContextIdKey[];
+extern const char kCtrlKeyKey[];
extern const char kCursorVisibleKey[];
+extern const char kEnabledKey[];
extern const char kEndKey[];
extern const char kEngineIdKey[];
+extern const char kIconKey[];
extern const char kIdKey[];
+extern const char kItemsKey[];
+extern const char kKeyKey[];
extern const char kLabelKey[];
extern const char kPageSizeKey[];
+extern const char kParentIdKey[];
extern const char kPropertiesKey[];
extern const char kSegmentsKey[];
extern const char kSelectionEndKey[];
extern const char kSelectionStartKey[];
+extern const char kShiftKeyKey[];
+extern const char kShortcutKey[];
extern const char kStartKey[];
extern const char kStyleDoubleUnderline[];
extern const char kStyleKey[];
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c35c027..9875c6f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2364,6 +2364,7 @@
'browser/extensions/extension_info_private_apitest_chromeos.cc',
'browser/extensions/extension_infobar_apitest.cc',
'browser/extensions/extension_input_apitest.cc',
+ 'browser/extensions/extension_input_ime_apitest.cc',
'browser/extensions/extension_input_method_apitest.cc',
'browser/extensions/extension_input_ui_apitest.cc',
'browser/extensions/extension_install_ui_browsertest.cc',
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index 7388936..fc7cf67 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -3544,11 +3544,6 @@
"description": "ID of the engine to use",
"type": "string"
},
- "parentId": {
- "description": "ID of the parent menu item",
- "optional": true,
- "type": "string"
- },
"items": {
"description": "MenuItems to add. They will be added in the order they exist in the array.",
"type": "array",
@@ -3573,8 +3568,7 @@
"optional": true,
"description": "Used to create a shortcut key label. The IME should handle the shortcut key itself, however.",
"properties": {
- "key": {"type": "string", "description": "Value of the key being pressed"},
- "keyCode": {"type": "string", "description": "Value of the key being press, unmodified by control keys."},
+ "key": {"type": "string", "description": "Value of the shortcut key"},
"altKey": {"type": "boolean", "optional": true, "description": "Whether or not the ALT key is pressed."},
"ctrlKey": {"type": "boolean", "optional": true, "description": "Whether or not the CTRL key is pressed."},
"shiftKey": {"type": "boolean", "optional": true, "description": "Whether or not the SHIFT key is pressed."}
@@ -3632,7 +3626,6 @@
"description": "Used to create a shortcut key label. The IME should handle the shortcut key itself, however.",
"properties": {
"key": {"type": "string", "description": "Value of the key being pressed"},
- "keyCode": {"type": "string", "description": "Value of the key being press, unmodified by control keys."},
"altKey": {"type": "boolean", "optional": true, "description": "Whether or not the ALT key is pressed."},
"ctrlKey": {"type": "boolean", "optional": true, "description": "Whether or not the CTRL key is pressed."},
"shiftKey": {"type": "boolean", "optional": true, "description": "Whether or not the SHIFT key is pressed."}
diff --git a/chrome/test/data/extensions/api_test/input_ime/background.html b/chrome/test/data/extensions/api_test/input_ime/background.html
new file mode 100644
index 0000000..59bd0c1
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/input_ime/background.html
@@ -0,0 +1,41 @@
+<script>
+ function setMenuItemsTest() {
+ chrome.experimental.input.setMenuItems({
+ "engineID": "test",
+ "items": [{
+ "id": "Menu 1",
+ "label": "Menu 1",
+ "style": "check",
+ "visible": true,
+ "enabled": true
+ }, {
+ "id": "Menu 2",
+ "label": "Menu 2",
+ "style": "radio",
+ "visible": true,
+ "enabled": true
+ }]
+ }, function () {
+ chrome.test.assertNoLastError();
+ chrome.test.succeed();
+ });
+ }
+
+ function updateMenuItemsTest() {
+ chrome.experimental.input.updateMenuItems({
+ "engineID": "test",
+ "items": [{
+ "id": "Menu 1",
+ "enabled": false
+ }, {
+ "id": "Menu 2",
+ "visible": false,
+ }]
+ }, function () {
+ chrome.test.assertNoLastError();
+ chrome.test.succeed();
+ });
+ }
+
+ chrome.test.runTests([setMenuItemsTest, updateMenuItemsTest]);
+</script>
diff --git a/chrome/test/data/extensions/api_test/input_ime/manifest.json b/chrome/test/data/extensions/api_test/input_ime/manifest.json
new file mode 100644
index 0000000..752c86e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/input_ime/manifest.json
@@ -0,0 +1,17 @@
+{
+ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9fDu8apG3Dz72XTT3Ym1SfGt06tdowTlYQ+3lGlCbVpfnMOmewgRgYxzUtUPso9aQERZcmI2+7UtbWjtk6/usl9Hr7a1JBQwfaUoUygEe56ajUeZhe/ErkH5CXT84U0pokfPr5vMvc7RVPduU+UBiF0DnGb/hSpzz/1UhJ5H9AwIDAQAB",
+ "name": "experimental.input ime test",
+ "version": "0.1",
+ "description": "Input method ime tests.",
+ "background_page": "background.html",
+ "permissions": [ "input", "experimental" ],
+ "input_components": [{
+ "name": "Test IME",
+ "type": "ime",
+ "id": "test",
+ "description": "Test", // A user visible description
+ "language": "en", // The primary language this IME is used for
+ "layouts": ["us::eng"]
+ }]
+}
+