Index: chrome/browser/chromeos/input_method/input_method_manager.cc |
diff --git a/chrome/browser/chromeos/input_method/input_method_manager.cc b/chrome/browser/chromeos/input_method/input_method_manager.cc |
index 5cf84c749da8e03d55865d2cf461dc418e2e90ef..0b7c1839e7a0b30541283395391dd5bcf2a402d0 100644 |
--- a/chrome/browser/chromeos/input_method/input_method_manager.cc |
+++ b/chrome/browser/chromeos/input_method/input_method_manager.cc |
@@ -40,13 +40,68 @@ |
namespace { |
const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; |
+const size_t kMaxInputMethodsPerHotkey = 2; |
// For hotkey handling. |
-enum HotkeyEvents { |
+enum HotkeyEvent { |
+ // Global hotkeys. |
kPreviousInputMethod = 0, |
kNextInputMethod, |
+ // Input method specific hotkeys. |
+ kJapaneseInputMethod, |
+ kJapaneseLayout, |
+ kJapaneseInputMethodOrLayout, |
+ kKoreanInputMethodOrLayout, |
}; |
+// Details of the input method specific hotkeys. |
+const struct InputMethodSpecificHotkeySetting { |
+ const char* input_method_ids[kMaxInputMethodsPerHotkey]; |
+ int event_id; |
+ KeySym keysym; |
+ uint32 modifiers; |
+ bool trigger_on_press; // if true. false means 'trigger on release'. |
+} kInputMethodSpecificHotkeySettings[] = { |
+ { |
+ { "mozc-jp" }, |
+ kJapaneseInputMethod, |
+ XK_Henkan, |
+ 0x0, |
+ true, |
+ }, |
+ { |
+ { "xkb:jp::jpn" }, |
+ kJapaneseLayout, |
+ XK_Muhenkan, |
+ 0x0, |
+ true, |
+ }, |
+ { |
+ { "mozc-jp", "xkb:jp::jpn" }, |
+ kJapaneseInputMethodOrLayout, |
+ XK_Zenkaku_Hankaku, |
+ 0x0, |
+ true, |
+ }, |
+ { |
+ { "mozc-hangul", "xkb:kr:kr104:kor" }, |
+ kKoreanInputMethodOrLayout, |
+ XK_Hangul, |
+ 0x0, |
+ true, |
+ }, |
+ { |
+ { "mozc-hangul", "xkb:kr:kr104:kor" }, |
+ kKoreanInputMethodOrLayout, |
+ XK_space, |
+ ShiftMask, |
+ true, |
+ }, |
+}; |
+ |
+const size_t kInputMethodSpecificHotkeySettingsLen = |
+ arraysize(kInputMethodSpecificHotkeySettings); |
+ |
// Finds a property which has |new_prop.key| from |prop_list|, and replaces the |
// property with |new_prop|. Returns true if such a property is found. |
bool FindAndUpdateProperty( |
@@ -104,6 +159,19 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
ibus_controller_->AddObserver(this); |
ibus_controller_->Connect(); |
+ // Initialize extra_hotkeys_. |
+ for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) { |
+ const char* const* input_method_ids = |
+ kInputMethodSpecificHotkeySettings[i].input_method_ids; |
+ for (size_t j = 0; |
+ j < kMaxInputMethodsPerHotkey && input_method_ids[j]; |
+ ++j) { |
+ extra_hotkeys_.insert(std::make_pair( |
+ input_method_ids[j], &kInputMethodSpecificHotkeySettings[i])); |
+ } |
+ } |
+ |
+ // Register global input method hotkeys: Control+space and Shift+Alt. |
InitHotkeyManager(); |
} |
@@ -229,6 +297,8 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
ix != extra_input_method_ids_.end(); ++ix) { |
active_input_method_ids_.push_back(ix->first); |
} |
+ |
+ UpdateInputMethodSpecificHotkeys(); |
} |
// Before calling FlushImeConfig(), start input method process if necessary. |
@@ -248,6 +318,7 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
return pending_config_requests_.empty(); |
} |
+ // TODO(yusukes): Support input method specific hotkeys. |
virtual void AddActiveIme(const std::string& id, |
const std::string& name, |
const std::vector<std::string>& layouts, |
@@ -258,6 +329,8 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
InputMethodDescriptor::CreateInputMethodDescriptor( |
id, virtual_layouts, language); |
active_input_method_ids_.push_back(id); |
+ // TODO(yusukes): Call UpdateInputMethodSpecificHotkeys() here once IME |
+ // extension supports hotkeys. |
} |
virtual void RemoveActiveIme(const std::string& id) { |
@@ -268,8 +341,9 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
if (ix != active_input_method_ids_.end()) { |
active_input_method_ids_.erase(ix); |
} |
- |
extra_input_method_ids_.erase(id); |
+ // TODO(yusukes): Call UpdateInputMethodSpecificHotkeys() here once IME |
+ // extension supports hotkeys. |
} |
virtual bool GetExtraDescriptor(const std::string& id, |
@@ -349,16 +423,21 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
} |
virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { |
- switch (HotkeyEvents(event_id)) { |
+ const HotkeyEvent event = HotkeyEvent(event_id); |
+ switch (event) { |
case kPreviousInputMethod: |
SwitchToPreviousInputMethod(); |
break; |
case kNextInputMethod: |
SwitchToNextInputMethod(); |
break; |
+ case kJapaneseInputMethod: |
+ case kJapaneseLayout: |
+ case kJapaneseInputMethodOrLayout: |
+ case kKoreanInputMethodOrLayout: |
+ SwitchToInputMethod(event); |
+ break; |
} |
- // TODO(yusukes): handle engine specific hotkeys like Henkan, Muhenkan, and |
- // Hangul. |
} |
static InputMethodManagerImpl* GetInstance() { |
@@ -961,12 +1040,33 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
XK_Meta_R, |
ShiftMask | Mod1Mask, |
false); |
+ // Input method specific hotkeys will be added in SetImeConfig(). |
- // TODO(yusukes): Support engine specific hotkeys like XK_Henkan, Muhenkan, |
- // and Hangul. |
hotkey_manager_.AddObserver(this); |
} |
+ void UpdateInputMethodSpecificHotkeys() { |
+ // Remove all input method specific hotkeys first. |
+ for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) { |
+ hotkey_manager_.RemoveHotkey( |
+ kInputMethodSpecificHotkeySettings[i].event_id); |
+ } |
+ |
+ for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { |
+ typedef std::map<std::string, |
+ const InputMethodSpecificHotkeySetting*>::const_iterator Iter; |
+ std::pair<Iter, Iter> result = extra_hotkeys_.equal_range( |
+ active_input_method_ids_[i]); |
+ for (Iter iter = result.first; iter != result.second; ++iter) { |
+ hotkey_manager_.AddHotkey(iter->second->event_id, |
+ iter->second->keysym, |
+ iter->second->modifiers, |
+ iter->second->trigger_on_press); |
+ } |
+ } |
+ // TODO(yusukes): Check hotkeys for IME extensions. |
+ } |
+ |
// Handles "Shift+Alt" hotkey. |
void SwitchToNextInputMethod() { |
// Sanity checks. |
@@ -1019,6 +1119,69 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
} |
} |
+ // Handles input method specific hotkeys like XK_Henkan. |
+ void SwitchToInputMethod(HotkeyEvent event) { |
+ // Sanity check. |
+ if (active_input_method_ids_.empty()) { |
+ LOG(ERROR) << "active input method is empty"; |
+ return; |
+ } |
+ |
+ // Get the list of input method ids for |event_id|. For example, get |
+ // { "mozc-hangul", "xkb:kr:kr104:kor" } for kKoreanInputMethodOrLayout. |
+ const char* const* input_method_ids_to_switch = NULL; |
+ switch (event) { |
+ case kPreviousInputMethod: |
+ case kNextInputMethod: |
+ // These events should not be handled here. |
+ break; |
+ case kJapaneseInputMethod: |
+ case kJapaneseLayout: |
+ case kJapaneseInputMethodOrLayout: |
+ case kKoreanInputMethodOrLayout: |
+ for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) { |
+ if (event == kInputMethodSpecificHotkeySettings[i].event_id) { |
+ input_method_ids_to_switch = |
+ kInputMethodSpecificHotkeySettings[i].input_method_ids; |
+ } |
+ } |
+ break; |
+ } |
+ if (!input_method_ids_to_switch) { |
+ LOG(ERROR) << "Unknown event: " << event; |
+ return; |
+ } |
+ |
+ // Obtain the intersection of input_method_ids_to_switch and |
+ // active_input_method_ids_. The order of IDs in active_input_method_ids_ is |
+ // preserved. |
+ std::vector<std::string> ids; |
+ for (size_t i = 0; i < kMaxInputMethodsPerHotkey; ++i) { |
+ const char* id = input_method_ids_to_switch[i]; |
+ if (id && std::find(active_input_method_ids_.begin(), |
+ active_input_method_ids_.end(), |
+ id) != active_input_method_ids_.end()) { |
+ ids.push_back(id); |
+ } |
+ } |
+ if (ids.empty()) { |
+ LOG(ERROR) << "No input method for " << event << " is active"; |
+ return; |
+ } |
+ |
+ // If current_input_method_ is not in ids, switch to ids[0]. If |
+ // current_input_method_ is ids[N], switch to ids[N+1]. |
+ std::vector<std::string>::const_iterator iter = |
+ std::find(ids.begin(), ids.end(), current_input_method_.id()); |
+ if (iter != ids.end()) { |
+ ++iter; |
+ } |
+ if (iter == ids.end()) { |
+ iter = ids.begin(); |
+ } |
+ ChangeInputMethod(*iter); |
+ } |
+ |
// A reference to the language api, to allow callbacks when the input method |
// status changes. |
IBusController* ibus_controller_; |
@@ -1088,6 +1251,10 @@ class InputMethodManagerImpl : public HotkeyManager::Observer, |
// those created by extension. |
std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; |
+ // A muitlmap from input method id to input method specific hotkey |
+ // information. e.g. "mozc-jp" to XK_ZenkakuHankaku, "mozc-jp" to XK_Henkan. |
+ std::multimap<std::string, |
+ const InputMethodSpecificHotkeySetting*> extra_hotkeys_; |
// An object which detects Control+space and Shift+Alt key presses. |
HotkeyManager hotkey_manager_; |