OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/input_method/input_method_manager.h" | 5 #include "chrome/browser/chromeos/input_method/input_method_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include <glib.h> | 9 #include <glib.h> |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... | |
35 #endif | 35 #endif |
36 | 36 |
37 #include <X11/X.h> // ShiftMask, ControlMask, etc. | 37 #include <X11/X.h> // ShiftMask, ControlMask, etc. |
38 #include <X11/Xutil.h> // for XK_* macros. | 38 #include <X11/Xutil.h> // for XK_* macros. |
39 | 39 |
40 namespace { | 40 namespace { |
41 | 41 |
42 const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; | 42 const char kIBusDaemonPath[] = "/usr/bin/ibus-daemon"; |
43 | 43 |
44 // For hotkey handling. | 44 // For hotkey handling. |
45 enum HotkeyEvents { | 45 enum HotkeyEvent { |
46 kPreviousInputMethod = 0, | 46 kPreviousInputMethod = 0, |
47 kNextInputMethod, | 47 kNextInputMethod, |
48 kJapaneseInputMethod, | |
49 kJapaneseLayout, | |
50 kJapaneseInputMethodOrLayout, | |
51 kKoreanInputMethodOrLayout, | |
52 }; | |
53 | |
54 // Engine specific hotkeys. | |
55 const struct EngineSpecificHotkeySetting { | |
56 const char* input_method_ids[2]; | |
57 int event_id; | |
58 KeySym keysym; | |
59 uint32 modifiers; | |
60 bool trigger_on_press; | |
mazda
2011/09/12 10:02:54
What happens if trigger_on_press is false?
Yusuke Sato
2011/09/12 11:46:05
IME or layout is changed on key release. The Shift
mazda
2011/09/12 11:57:31
Thanks.
Probably it's better to add comment since
Yusuke Sato
2011/09/12 12:02:14
Done.
| |
61 } kEngineSpecificHotkeySettings[] = { | |
62 { | |
63 { "mozc-jp" }, | |
64 kJapaneseInputMethod, | |
65 XK_Henkan, | |
66 0x0, | |
67 true, | |
68 }, | |
69 { | |
70 { "xkb:jp::jpn" }, | |
71 kJapaneseLayout, | |
72 XK_Muhenkan, | |
73 0x0, | |
74 true, | |
75 }, | |
76 { | |
77 { "mozc-jp", "xkb:jp::jpn" }, | |
78 kJapaneseInputMethodOrLayout, | |
79 XK_Zenkaku_Hankaku, | |
80 0x0, | |
81 true, | |
82 }, | |
83 { | |
84 { "mozc-hangul", "xkb:kr:kr104:kor" }, | |
85 kKoreanInputMethodOrLayout, | |
86 XK_Hangul, | |
87 0x0, | |
88 true, | |
89 }, | |
90 { | |
91 { "mozc-hangul", "xkb:kr:kr104:kor" }, | |
92 kKoreanInputMethodOrLayout, | |
93 XK_space, | |
94 ShiftMask, | |
95 true, | |
96 }, | |
48 }; | 97 }; |
49 | 98 |
50 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the | 99 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the |
51 // property with |new_prop|. Returns true if such a property is found. | 100 // property with |new_prop|. Returns true if such a property is found. |
52 bool FindAndUpdateProperty( | 101 bool FindAndUpdateProperty( |
53 const chromeos::input_method::ImeProperty& new_prop, | 102 const chromeos::input_method::ImeProperty& new_prop, |
54 chromeos::input_method::ImePropertyList* prop_list) { | 103 chromeos::input_method::ImePropertyList* prop_list) { |
55 for (size_t i = 0; i < prop_list->size(); ++i) { | 104 for (size_t i = 0; i < prop_list->size(); ++i) { |
56 chromeos::input_method::ImeProperty& prop = prop_list->at(i); | 105 chromeos::input_method::ImeProperty& prop = prop_list->at(i); |
57 if (prop.key == new_prop.key) { | 106 if (prop.key == new_prop.key) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 // details. | 146 // details. |
98 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, | 147 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, |
99 NotificationService::AllSources()); | 148 NotificationService::AllSources()); |
100 | 149 |
101 ibus_controller_ = IBusController::Create(); | 150 ibus_controller_ = IBusController::Create(); |
102 // The observer should be added before Connect() so we can capture the | 151 // The observer should be added before Connect() so we can capture the |
103 // initial connection change. | 152 // initial connection change. |
104 ibus_controller_->AddObserver(this); | 153 ibus_controller_->AddObserver(this); |
105 ibus_controller_->Connect(); | 154 ibus_controller_->Connect(); |
106 | 155 |
156 // Initialize engine_hotkeys_. | |
157 for (size_t i = 0; i < arraysize(kEngineSpecificHotkeySettings); ++i) { | |
158 const char* const* input_method_ids = | |
159 kEngineSpecificHotkeySettings[i].input_method_ids; | |
160 const size_t input_method_ids_len = | |
161 arraysize(kEngineSpecificHotkeySettings[i].input_method_ids); | |
162 for (size_t j = 0; j < input_method_ids_len && input_method_ids[j]; ++j) { | |
163 engine_hotkeys_.insert(std::make_pair( | |
164 input_method_ids[j], &kEngineSpecificHotkeySettings[i])); | |
165 } | |
166 } | |
167 | |
168 // Register global input method hotkeys: Control+space and Shift+Alt. | |
107 InitHotkeyManager(); | 169 InitHotkeyManager(); |
108 } | 170 } |
109 | 171 |
110 virtual ~InputMethodManagerImpl() { | 172 virtual ~InputMethodManagerImpl() { |
111 hotkey_manager_.RemoveObserver(this); | 173 hotkey_manager_.RemoveObserver(this); |
112 ibus_controller_->RemoveObserver(this); | 174 ibus_controller_->RemoveObserver(this); |
113 } | 175 } |
114 | 176 |
115 virtual void AddObserver(InputMethodManager::Observer* observer) { | 177 virtual void AddObserver(InputMethodManager::Observer* observer) { |
116 if (!observers_.size()) { | 178 if (!observers_.size()) { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 // input methods cache |active_input_method_ids_| here. We need to | 278 // input methods cache |active_input_method_ids_| here. We need to |
217 // update the cache before actually flushing the config. since we need | 279 // update the cache before actually flushing the config. since we need |
218 // to return active input methods from GetActiveInputMethods() before | 280 // to return active input methods from GetActiveInputMethods() before |
219 // the input method daemon starts. For instance, we need to show the | 281 // the input method daemon starts. For instance, we need to show the |
220 // list of available input methods (keyboard layouts) on the login | 282 // list of available input methods (keyboard layouts) on the login |
221 // screen before the input method starts. | 283 // screen before the input method starts. |
222 if (section == language_prefs::kGeneralSectionName && | 284 if (section == language_prefs::kGeneralSectionName && |
223 config_name == language_prefs::kPreloadEnginesConfigName && | 285 config_name == language_prefs::kPreloadEnginesConfigName && |
224 value.type == ImeConfigValue::kValueTypeStringList) { | 286 value.type == ImeConfigValue::kValueTypeStringList) { |
225 active_input_method_ids_ = value.string_list_value; | 287 active_input_method_ids_ = value.string_list_value; |
288 UpdateEngineSpecificHotkeys(); | |
mazda
2011/09/12 10:02:54
Is it OK that UpdateEngineSpecificHotkeys is calle
Yusuke Sato
2011/09/12 11:46:05
For now it's okay since hotkey information for an
| |
226 | 289 |
227 std::map<std::string, InputMethodDescriptor>::const_iterator ix; | 290 std::map<std::string, InputMethodDescriptor>::const_iterator ix; |
228 for (ix = extra_input_method_ids_.begin(); | 291 for (ix = extra_input_method_ids_.begin(); |
229 ix != extra_input_method_ids_.end(); ++ix) { | 292 ix != extra_input_method_ids_.end(); ++ix) { |
230 active_input_method_ids_.push_back(ix->first); | 293 active_input_method_ids_.push_back(ix->first); |
231 } | 294 } |
232 } | 295 } |
233 | 296 |
234 // Before calling FlushImeConfig(), start input method process if necessary. | 297 // Before calling FlushImeConfig(), start input method process if necessary. |
235 MaybeStartInputMethodDaemon(section, config_name, value); | 298 MaybeStartInputMethodDaemon(section, config_name, value); |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
342 virtual void ClearAllVirtualKeyboardPreferences() { | 405 virtual void ClearAllVirtualKeyboardPreferences() { |
343 virtual_keyboard_selector_.ClearAllUserPreferences(); | 406 virtual_keyboard_selector_.ClearAllUserPreferences(); |
344 UpdateVirtualKeyboardUI(); | 407 UpdateVirtualKeyboardUI(); |
345 } | 408 } |
346 | 409 |
347 virtual HotkeyManager* GetHotkeyManager() { | 410 virtual HotkeyManager* GetHotkeyManager() { |
348 return &hotkey_manager_; | 411 return &hotkey_manager_; |
349 } | 412 } |
350 | 413 |
351 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { | 414 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { |
352 switch (HotkeyEvents(event_id)) { | 415 const HotkeyEvent event = HotkeyEvent(event_id); |
416 switch (event) { | |
353 case kPreviousInputMethod: | 417 case kPreviousInputMethod: |
354 SwitchToPreviousInputMethod(); | 418 SwitchToPreviousInputMethod(); |
355 break; | 419 break; |
356 case kNextInputMethod: | 420 case kNextInputMethod: |
357 SwitchToNextInputMethod(); | 421 SwitchToNextInputMethod(); |
358 break; | 422 break; |
423 case kJapaneseInputMethod: | |
424 case kJapaneseLayout: | |
425 case kJapaneseInputMethodOrLayout: | |
426 case kKoreanInputMethodOrLayout: | |
427 SwitchToInputMethod(event); | |
mazda
2011/09/12 10:02:54
default case.
Yusuke Sato
2011/09/12 11:46:05
Since HotkeyEvent is an enum, adding default: is n
| |
428 break; | |
359 } | 429 } |
360 // TODO(yusukes): handle engine specific hotkeys like Henkan, Muhenkan, and | |
361 // Hangul. | |
362 } | 430 } |
363 | 431 |
364 static InputMethodManagerImpl* GetInstance() { | 432 static InputMethodManagerImpl* GetInstance() { |
365 return Singleton<InputMethodManagerImpl, | 433 return Singleton<InputMethodManagerImpl, |
366 DefaultSingletonTraits<InputMethodManagerImpl> >::get(); | 434 DefaultSingletonTraits<InputMethodManagerImpl> >::get(); |
367 } | 435 } |
368 | 436 |
369 private: | 437 private: |
370 friend struct DefaultSingletonTraits<InputMethodManagerImpl>; | 438 friend struct DefaultSingletonTraits<InputMethodManagerImpl>; |
371 | 439 |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
954 ShiftMask | Mod1Mask, | 1022 ShiftMask | Mod1Mask, |
955 false); | 1023 false); |
956 hotkey_manager_.AddHotkey(kNextInputMethod, | 1024 hotkey_manager_.AddHotkey(kNextInputMethod, |
957 XK_Meta_L, | 1025 XK_Meta_L, |
958 ShiftMask | Mod1Mask, | 1026 ShiftMask | Mod1Mask, |
959 false); | 1027 false); |
960 hotkey_manager_.AddHotkey(kNextInputMethod, | 1028 hotkey_manager_.AddHotkey(kNextInputMethod, |
961 XK_Meta_R, | 1029 XK_Meta_R, |
962 ShiftMask | Mod1Mask, | 1030 ShiftMask | Mod1Mask, |
963 false); | 1031 false); |
1032 // Engine specific hotkeys will be added in SetImeConfig(). | |
964 | 1033 |
965 // TODO(yusukes): Support engine specific hotkeys like XK_Henkan, Muhenkan, | |
966 // and Hangul. | |
967 hotkey_manager_.AddObserver(this); | 1034 hotkey_manager_.AddObserver(this); |
968 } | 1035 } |
969 | 1036 |
1037 void UpdateEngineSpecificHotkeys() { | |
1038 // Remove all engine specific hotkeys first. | |
1039 for (size_t i = 0; i < arraysize(kEngineSpecificHotkeySettings); ++i) { | |
1040 hotkey_manager_.RemoveHotkey(kEngineSpecificHotkeySettings[i].event_id); | |
1041 } | |
1042 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) { | |
1043 typedef std::map<std::string, | |
1044 const EngineSpecificHotkeySetting*>::const_iterator Iter; | |
1045 std::pair<Iter, Iter> result = engine_hotkeys_.equal_range( | |
1046 active_input_method_ids_[i]); | |
1047 for (Iter iter = result.first; iter != result.second; ++iter) { | |
1048 hotkey_manager_.AddHotkey(iter->second->event_id, | |
1049 iter->second->keysym, | |
1050 iter->second->modifiers, | |
1051 iter->second->trigger_on_press); | |
1052 } | |
1053 } | |
1054 } | |
1055 | |
970 // Handles "Shift+Alt" hotkey. | 1056 // Handles "Shift+Alt" hotkey. |
971 void SwitchToNextInputMethod() { | 1057 void SwitchToNextInputMethod() { |
972 // Sanity checks. | 1058 // Sanity checks. |
973 if (active_input_method_ids_.empty()) { | 1059 if (active_input_method_ids_.empty()) { |
974 LOG(ERROR) << "active input method is empty"; | 1060 LOG(ERROR) << "active input method is empty"; |
975 return; | 1061 return; |
976 } | 1062 } |
977 if (current_input_method_.id().empty()) { | 1063 if (current_input_method_.id().empty()) { |
978 LOG(ERROR) << "current_input_method_ is unknown"; | 1064 LOG(ERROR) << "current_input_method_ is unknown"; |
979 return; | 1065 return; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1012 active_input_method_ids_.end(), | 1098 active_input_method_ids_.end(), |
1013 previous_input_method_.id()); | 1099 previous_input_method_.id()); |
1014 if (iter == active_input_method_ids_.end()) { | 1100 if (iter == active_input_method_ids_.end()) { |
1015 // previous_input_method_ is not supported. | 1101 // previous_input_method_ is not supported. |
1016 SwitchToNextInputMethod(); | 1102 SwitchToNextInputMethod(); |
1017 } else { | 1103 } else { |
1018 ChangeInputMethod(*iter); | 1104 ChangeInputMethod(*iter); |
1019 } | 1105 } |
1020 } | 1106 } |
1021 | 1107 |
1108 // Handles engine specific hotkeys like XK_Henkan. | |
1109 void SwitchToInputMethod(HotkeyEvent event) { | |
1110 // Sanity check. | |
1111 if (active_input_method_ids_.empty()) { | |
1112 LOG(ERROR) << "active input method is empty"; | |
1113 return; | |
1114 } | |
1115 | |
1116 const char* const* input_method_ids_to_switch = NULL; | |
1117 size_t input_method_ids_to_switch_len = 0; | |
1118 | |
1119 // Get the list of input method ids for |event_id|. For example, get | |
1120 // { "mozc-hangul", "xkb:kr:kr104:kor" } for kKoreanInputMethodOrLayout. | |
1121 switch (event) { | |
1122 case kPreviousInputMethod: | |
1123 case kNextInputMethod: { | |
1124 break; | |
mazda
2011/09/12 10:02:54
Are these two error case?
Yusuke Sato
2011/09/12 11:46:05
added a comment.
| |
1125 } | |
1126 case kJapaneseInputMethod: | |
1127 case kJapaneseLayout: | |
1128 case kJapaneseInputMethodOrLayout: | |
1129 case kKoreanInputMethodOrLayout: { | |
1130 const size_t index = static_cast<size_t>(event) - 2; | |
Zachary Kuznia
2011/09/12 09:48:07
This line looks scary. Please give it a reassurin
Yusuke Sato
2011/09/12 11:46:05
Probably this was too error-prone. I've written th
| |
1131 DCHECK(event == kEngineSpecificHotkeySettings[index].event_id); | |
1132 input_method_ids_to_switch = | |
1133 kEngineSpecificHotkeySettings[index].input_method_ids; | |
1134 input_method_ids_to_switch_len = | |
1135 arraysize(kEngineSpecificHotkeySettings[index].input_method_ids); | |
1136 break; | |
1137 } | |
1138 } | |
1139 if (!input_method_ids_to_switch) { | |
mazda
2011/09/12 10:02:54
How about moving this to the default case of the s
Yusuke Sato
2011/09/12 11:46:05
ditto. I prefer not to use default: in order to ke
| |
1140 LOG(ERROR) << "Unknown event: " << event; | |
1141 return; | |
1142 } | |
1143 | |
1144 // Obtain the intersection of input_method_ids_to_switch and | |
1145 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is | |
1146 // preserved. | |
1147 std::vector<std::string> ids; | |
1148 for (size_t i = 0; i < input_method_ids_to_switch_len; ++i) { | |
1149 const char* id = input_method_ids_to_switch[i]; | |
1150 if (id && std::find(active_input_method_ids_.begin(), | |
1151 active_input_method_ids_.end(), | |
1152 id) != active_input_method_ids_.end()) { | |
1153 ids.push_back(id); | |
1154 } | |
1155 } | |
1156 if (ids.empty()) { | |
1157 LOG(ERROR) << "No input method for " << event << " is active"; | |
1158 return; | |
1159 } | |
1160 | |
1161 // If current_input_method_ is not in ids, switch to ids[0]. If | |
1162 // current_input_method_ is ids[N], switch to ids[N+1]. | |
1163 std::vector<std::string>::const_iterator iter = | |
1164 std::find(ids.begin(), ids.end(), current_input_method_.id()); | |
1165 if (iter != ids.end()) { | |
1166 ++iter; | |
1167 } | |
1168 if (iter == ids.end()) { | |
1169 iter = ids.begin(); | |
1170 } | |
1171 ChangeInputMethod(*iter); | |
1172 } | |
1173 | |
1022 // A reference to the language api, to allow callbacks when the input method | 1174 // A reference to the language api, to allow callbacks when the input method |
1023 // status changes. | 1175 // status changes. |
1024 IBusController* ibus_controller_; | 1176 IBusController* ibus_controller_; |
1025 ObserverList<InputMethodManager::Observer> observers_; | 1177 ObserverList<InputMethodManager::Observer> observers_; |
1026 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; | 1178 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; |
1027 | 1179 |
1028 // The input method which was/is selected. | 1180 // The input method which was/is selected. |
1029 InputMethodDescriptor previous_input_method_; | 1181 InputMethodDescriptor previous_input_method_; |
1030 InputMethodDescriptor current_input_method_; | 1182 InputMethodDescriptor current_input_method_; |
1031 | 1183 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1081 // An object which keeps a list of available virtual keyboards. | 1233 // An object which keeps a list of available virtual keyboards. |
1082 VirtualKeyboardSelector virtual_keyboard_selector_; | 1234 VirtualKeyboardSelector virtual_keyboard_selector_; |
1083 | 1235 |
1084 // The active input method ids cache. | 1236 // The active input method ids cache. |
1085 std::vector<std::string> active_input_method_ids_; | 1237 std::vector<std::string> active_input_method_ids_; |
1086 | 1238 |
1087 // Extra input methods that have been explicitly added to the menu, such as | 1239 // Extra input methods that have been explicitly added to the menu, such as |
1088 // those created by extension. | 1240 // those created by extension. |
1089 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; | 1241 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; |
1090 | 1242 |
1243 // A muitlmap from input method id to engine specific hotkey information. | |
1244 // e.g. "mozc-jp" to XK_ZenkakuHankaku, "mozc-jp" to XK_Henkan. | |
1245 std::multimap<std::string, | |
1246 const EngineSpecificHotkeySetting*> engine_hotkeys_; | |
1091 // An object which detects Control+space and Shift+Alt key presses. | 1247 // An object which detects Control+space and Shift+Alt key presses. |
1092 HotkeyManager hotkey_manager_; | 1248 HotkeyManager hotkey_manager_; |
1093 | 1249 |
1094 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); | 1250 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); |
1095 }; | 1251 }; |
1096 | 1252 |
1097 // static | 1253 // static |
1098 InputMethodManager* InputMethodManager::GetInstance() { | 1254 InputMethodManager* InputMethodManager::GetInstance() { |
1099 return InputMethodManagerImpl::GetInstance(); | 1255 return InputMethodManagerImpl::GetInstance(); |
1100 } | 1256 } |
1101 | 1257 |
1102 } // namespace input_method | 1258 } // namespace input_method |
1103 } // namespace chromeos | 1259 } // namespace chromeos |
1104 | 1260 |
1105 // Allows InvokeLater without adding refcounting. This class is a Singleton and | 1261 // Allows InvokeLater without adding refcounting. This class is a Singleton and |
1106 // won't be deleted until it's last InvokeLater is run. | 1262 // won't be deleted until it's last InvokeLater is run. |
1107 DISABLE_RUNNABLE_METHOD_REFCOUNT( | 1263 DISABLE_RUNNABLE_METHOD_REFCOUNT( |
1108 chromeos::input_method::InputMethodManagerImpl); | 1264 chromeos::input_method::InputMethodManagerImpl); |
OLD | NEW |