diff options
author | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-12 07:01:27 +0000 |
---|---|---|
committer | zork@chromium.org <zork@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-12 07:01:27 +0000 |
commit | 817925aaf716cb623c56e21030650f075e510157 (patch) | |
tree | 7fa202867b8025e0556622a5c48143ec256860f3 | |
parent | c24e5d45e49e3241332b7df30d925ba684d35b61 (diff) | |
download | chromium_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
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"] + }] +} + |