Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(833)

Side by Side Diff: chrome/browser/chromeos/input_method/input_method_manager.cc

Issue 7865019: Handle XK_Zenkaku_Hankaku, Henkan, Muhenkan, Hangul etc. in Chrome (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review fix Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 22 matching lines...) Expand all
33 #if !defined(TOUCH_UI) 33 #if !defined(TOUCH_UI)
34 #include "chrome/browser/chromeos/input_method/candidate_window.h" 34 #include "chrome/browser/chromeos/input_method/candidate_window.h"
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 const size_t kMaxInputMethodsPerHotkey = 2;
43 44
44 // For hotkey handling. 45 // For hotkey handling.
45 enum HotkeyEvents { 46 enum HotkeyEvent {
47 // Global hotkeys.
46 kPreviousInputMethod = 0, 48 kPreviousInputMethod = 0,
47 kNextInputMethod, 49 kNextInputMethod,
50 // Input method specific hotkeys.
51 kJapaneseInputMethod,
52 kJapaneseLayout,
53 kJapaneseInputMethodOrLayout,
54 kKoreanInputMethodOrLayout,
48 }; 55 };
49 56
57 // Details of the input method specific hotkeys.
58 const struct InputMethodSpecificHotkeySetting {
59 const char* input_method_ids[kMaxInputMethodsPerHotkey];
60 int event_id;
61 KeySym keysym;
62 uint32 modifiers;
63 bool trigger_on_press; // if true. false means 'trigger on release'.
64 } kInputMethodSpecificHotkeySettings[] = {
65 {
66 { "mozc-jp" },
67 kJapaneseInputMethod,
68 XK_Henkan,
69 0x0,
70 true,
71 },
72 {
73 { "xkb:jp::jpn" },
74 kJapaneseLayout,
75 XK_Muhenkan,
76 0x0,
77 true,
78 },
79 {
80 { "mozc-jp", "xkb:jp::jpn" },
81 kJapaneseInputMethodOrLayout,
82 XK_Zenkaku_Hankaku,
83 0x0,
84 true,
85 },
86 {
87 { "mozc-hangul", "xkb:kr:kr104:kor" },
88 kKoreanInputMethodOrLayout,
89 XK_Hangul,
90 0x0,
91 true,
92 },
93 {
94 { "mozc-hangul", "xkb:kr:kr104:kor" },
95 kKoreanInputMethodOrLayout,
96 XK_space,
97 ShiftMask,
98 true,
99 },
100 };
101
102 const size_t kInputMethodSpecificHotkeySettingsLen =
103 arraysize(kInputMethodSpecificHotkeySettings);
104
50 // Finds a property which has |new_prop.key| from |prop_list|, and replaces the 105 // 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. 106 // property with |new_prop|. Returns true if such a property is found.
52 bool FindAndUpdateProperty( 107 bool FindAndUpdateProperty(
53 const chromeos::input_method::ImeProperty& new_prop, 108 const chromeos::input_method::ImeProperty& new_prop,
54 chromeos::input_method::ImePropertyList* prop_list) { 109 chromeos::input_method::ImePropertyList* prop_list) {
55 for (size_t i = 0; i < prop_list->size(); ++i) { 110 for (size_t i = 0; i < prop_list->size(); ++i) {
56 chromeos::input_method::ImeProperty& prop = prop_list->at(i); 111 chromeos::input_method::ImeProperty& prop = prop_list->at(i);
57 if (prop.key == new_prop.key) { 112 if (prop.key == new_prop.key) {
58 const int saved_id = prop.selection_item_id; 113 const int saved_id = prop.selection_item_id;
59 // Update the list except the radio id. As written in 114 // Update the list except the radio id. As written in
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 // details. 152 // details.
98 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING, 153 notification_registrar_.Add(this, content::NOTIFICATION_APP_TERMINATING,
99 NotificationService::AllSources()); 154 NotificationService::AllSources());
100 155
101 ibus_controller_ = IBusController::Create(); 156 ibus_controller_ = IBusController::Create();
102 // The observer should be added before Connect() so we can capture the 157 // The observer should be added before Connect() so we can capture the
103 // initial connection change. 158 // initial connection change.
104 ibus_controller_->AddObserver(this); 159 ibus_controller_->AddObserver(this);
105 ibus_controller_->Connect(); 160 ibus_controller_->Connect();
106 161
162 // Initialize extra_hotkeys_.
163 for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) {
164 const char* const* input_method_ids =
165 kInputMethodSpecificHotkeySettings[i].input_method_ids;
166 for (size_t j = 0;
167 j < kMaxInputMethodsPerHotkey && input_method_ids[j];
168 ++j) {
169 extra_hotkeys_.insert(std::make_pair(
170 input_method_ids[j], &kInputMethodSpecificHotkeySettings[i]));
171 }
172 }
173
174 // Register global input method hotkeys: Control+space and Shift+Alt.
107 InitHotkeyManager(); 175 InitHotkeyManager();
108 } 176 }
109 177
110 virtual ~InputMethodManagerImpl() { 178 virtual ~InputMethodManagerImpl() {
111 hotkey_manager_.RemoveObserver(this); 179 hotkey_manager_.RemoveObserver(this);
112 ibus_controller_->RemoveObserver(this); 180 ibus_controller_->RemoveObserver(this);
113 } 181 }
114 182
115 virtual void AddObserver(InputMethodManager::Observer* observer) { 183 virtual void AddObserver(InputMethodManager::Observer* observer) {
116 if (!observers_.size()) { 184 if (!observers_.size()) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 if (section == language_prefs::kGeneralSectionName && 290 if (section == language_prefs::kGeneralSectionName &&
223 config_name == language_prefs::kPreloadEnginesConfigName && 291 config_name == language_prefs::kPreloadEnginesConfigName &&
224 value.type == ImeConfigValue::kValueTypeStringList) { 292 value.type == ImeConfigValue::kValueTypeStringList) {
225 active_input_method_ids_ = value.string_list_value; 293 active_input_method_ids_ = value.string_list_value;
226 294
227 std::map<std::string, InputMethodDescriptor>::const_iterator ix; 295 std::map<std::string, InputMethodDescriptor>::const_iterator ix;
228 for (ix = extra_input_method_ids_.begin(); 296 for (ix = extra_input_method_ids_.begin();
229 ix != extra_input_method_ids_.end(); ++ix) { 297 ix != extra_input_method_ids_.end(); ++ix) {
230 active_input_method_ids_.push_back(ix->first); 298 active_input_method_ids_.push_back(ix->first);
231 } 299 }
300
301 UpdateInputMethodSpecificHotkeys();
232 } 302 }
233 303
234 // Before calling FlushImeConfig(), start input method process if necessary. 304 // Before calling FlushImeConfig(), start input method process if necessary.
235 MaybeStartInputMethodDaemon(section, config_name, value); 305 MaybeStartInputMethodDaemon(section, config_name, value);
236 306
237 const ConfigKeyType key = std::make_pair(section, config_name); 307 const ConfigKeyType key = std::make_pair(section, config_name);
238 current_config_values_[key] = value; 308 current_config_values_[key] = value;
239 if (ime_connected_) { 309 if (ime_connected_) {
240 pending_config_requests_[key] = value; 310 pending_config_requests_[key] = value;
241 FlushImeConfig(); 311 FlushImeConfig();
242 } 312 }
243 313
244 // Stop input method process if necessary. 314 // Stop input method process if necessary.
245 MaybeStopInputMethodDaemon(section, config_name, value); 315 MaybeStopInputMethodDaemon(section, config_name, value);
246 // Change the current keyboard layout if necessary. 316 // Change the current keyboard layout if necessary.
247 MaybeChangeCurrentKeyboardLayout(section, config_name, value); 317 MaybeChangeCurrentKeyboardLayout(section, config_name, value);
248 return pending_config_requests_.empty(); 318 return pending_config_requests_.empty();
249 } 319 }
250 320
321 // TODO(yusukes): Support input method specific hotkeys.
251 virtual void AddActiveIme(const std::string& id, 322 virtual void AddActiveIme(const std::string& id,
252 const std::string& name, 323 const std::string& name,
253 const std::vector<std::string>& layouts, 324 const std::vector<std::string>& layouts,
254 const std::string& language) { 325 const std::string& language) {
255 std::string virtual_layouts = JoinString(layouts, ','); 326 std::string virtual_layouts = JoinString(layouts, ',');
256 327
257 extra_input_method_ids_[id] = 328 extra_input_method_ids_[id] =
258 InputMethodDescriptor::CreateInputMethodDescriptor( 329 InputMethodDescriptor::CreateInputMethodDescriptor(
259 id, virtual_layouts, language); 330 id, virtual_layouts, language);
260 active_input_method_ids_.push_back(id); 331 active_input_method_ids_.push_back(id);
332 // TODO(yusukes): Call UpdateInputMethodSpecificHotkeys() here once IME
333 // extension supports hotkeys.
261 } 334 }
262 335
263 virtual void RemoveActiveIme(const std::string& id) { 336 virtual void RemoveActiveIme(const std::string& id) {
264 std::vector<std::string>::iterator ix = 337 std::vector<std::string>::iterator ix =
265 std::find(active_input_method_ids_.begin(), 338 std::find(active_input_method_ids_.begin(),
266 active_input_method_ids_.end(), 339 active_input_method_ids_.end(),
267 id); 340 id);
268 if (ix != active_input_method_ids_.end()) { 341 if (ix != active_input_method_ids_.end()) {
269 active_input_method_ids_.erase(ix); 342 active_input_method_ids_.erase(ix);
270 } 343 }
271
272 extra_input_method_ids_.erase(id); 344 extra_input_method_ids_.erase(id);
345 // TODO(yusukes): Call UpdateInputMethodSpecificHotkeys() here once IME
346 // extension supports hotkeys.
273 } 347 }
274 348
275 virtual bool GetExtraDescriptor(const std::string& id, 349 virtual bool GetExtraDescriptor(const std::string& id,
276 InputMethodDescriptor* descriptor) { 350 InputMethodDescriptor* descriptor) {
277 std::map<std::string, InputMethodDescriptor>::const_iterator ix = 351 std::map<std::string, InputMethodDescriptor>::const_iterator ix =
278 extra_input_method_ids_.find(id); 352 extra_input_method_ids_.find(id);
279 if (ix != extra_input_method_ids_.end()) { 353 if (ix != extra_input_method_ids_.end()) {
280 *descriptor = ix->second; 354 *descriptor = ix->second;
281 return true; 355 return true;
282 } else { 356 } else {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 virtual void ClearAllVirtualKeyboardPreferences() { 416 virtual void ClearAllVirtualKeyboardPreferences() {
343 virtual_keyboard_selector_.ClearAllUserPreferences(); 417 virtual_keyboard_selector_.ClearAllUserPreferences();
344 UpdateVirtualKeyboardUI(); 418 UpdateVirtualKeyboardUI();
345 } 419 }
346 420
347 virtual HotkeyManager* GetHotkeyManager() { 421 virtual HotkeyManager* GetHotkeyManager() {
348 return &hotkey_manager_; 422 return &hotkey_manager_;
349 } 423 }
350 424
351 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) { 425 virtual void HotkeyPressed(HotkeyManager* manager, int event_id) {
352 switch (HotkeyEvents(event_id)) { 426 const HotkeyEvent event = HotkeyEvent(event_id);
427 switch (event) {
353 case kPreviousInputMethod: 428 case kPreviousInputMethod:
354 SwitchToPreviousInputMethod(); 429 SwitchToPreviousInputMethod();
355 break; 430 break;
356 case kNextInputMethod: 431 case kNextInputMethod:
357 SwitchToNextInputMethod(); 432 SwitchToNextInputMethod();
358 break; 433 break;
434 case kJapaneseInputMethod:
435 case kJapaneseLayout:
436 case kJapaneseInputMethodOrLayout:
437 case kKoreanInputMethodOrLayout:
438 SwitchToInputMethod(event);
439 break;
359 } 440 }
360 // TODO(yusukes): handle engine specific hotkeys like Henkan, Muhenkan, and
361 // Hangul.
362 } 441 }
363 442
364 static InputMethodManagerImpl* GetInstance() { 443 static InputMethodManagerImpl* GetInstance() {
365 return Singleton<InputMethodManagerImpl, 444 return Singleton<InputMethodManagerImpl,
366 DefaultSingletonTraits<InputMethodManagerImpl> >::get(); 445 DefaultSingletonTraits<InputMethodManagerImpl> >::get();
367 } 446 }
368 447
369 private: 448 private:
370 friend struct DefaultSingletonTraits<InputMethodManagerImpl>; 449 friend struct DefaultSingletonTraits<InputMethodManagerImpl>;
371 450
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 ShiftMask | Mod1Mask, 1033 ShiftMask | Mod1Mask,
955 false); 1034 false);
956 hotkey_manager_.AddHotkey(kNextInputMethod, 1035 hotkey_manager_.AddHotkey(kNextInputMethod,
957 XK_Meta_L, 1036 XK_Meta_L,
958 ShiftMask | Mod1Mask, 1037 ShiftMask | Mod1Mask,
959 false); 1038 false);
960 hotkey_manager_.AddHotkey(kNextInputMethod, 1039 hotkey_manager_.AddHotkey(kNextInputMethod,
961 XK_Meta_R, 1040 XK_Meta_R,
962 ShiftMask | Mod1Mask, 1041 ShiftMask | Mod1Mask,
963 false); 1042 false);
1043 // Input method specific hotkeys will be added in SetImeConfig().
964 1044
965 // TODO(yusukes): Support engine specific hotkeys like XK_Henkan, Muhenkan,
966 // and Hangul.
967 hotkey_manager_.AddObserver(this); 1045 hotkey_manager_.AddObserver(this);
968 } 1046 }
969 1047
1048 void UpdateInputMethodSpecificHotkeys() {
1049 // Remove all input method specific hotkeys first.
1050 for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) {
1051 hotkey_manager_.RemoveHotkey(
1052 kInputMethodSpecificHotkeySettings[i].event_id);
1053 }
1054
1055 for (size_t i = 0; i < active_input_method_ids_.size(); ++i) {
1056 typedef std::map<std::string,
1057 const InputMethodSpecificHotkeySetting*>::const_iterator Iter;
1058 std::pair<Iter, Iter> result = extra_hotkeys_.equal_range(
1059 active_input_method_ids_[i]);
1060 for (Iter iter = result.first; iter != result.second; ++iter) {
1061 hotkey_manager_.AddHotkey(iter->second->event_id,
1062 iter->second->keysym,
1063 iter->second->modifiers,
1064 iter->second->trigger_on_press);
1065 }
1066 }
1067 // TODO(yusukes): Check hotkeys for IME extensions.
1068 }
1069
970 // Handles "Shift+Alt" hotkey. 1070 // Handles "Shift+Alt" hotkey.
971 void SwitchToNextInputMethod() { 1071 void SwitchToNextInputMethod() {
972 // Sanity checks. 1072 // Sanity checks.
973 if (active_input_method_ids_.empty()) { 1073 if (active_input_method_ids_.empty()) {
974 LOG(ERROR) << "active input method is empty"; 1074 LOG(ERROR) << "active input method is empty";
975 return; 1075 return;
976 } 1076 }
977 if (current_input_method_.id().empty()) { 1077 if (current_input_method_.id().empty()) {
978 LOG(ERROR) << "current_input_method_ is unknown"; 1078 LOG(ERROR) << "current_input_method_ is unknown";
979 return; 1079 return;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 active_input_method_ids_.end(), 1112 active_input_method_ids_.end(),
1013 previous_input_method_.id()); 1113 previous_input_method_.id());
1014 if (iter == active_input_method_ids_.end()) { 1114 if (iter == active_input_method_ids_.end()) {
1015 // previous_input_method_ is not supported. 1115 // previous_input_method_ is not supported.
1016 SwitchToNextInputMethod(); 1116 SwitchToNextInputMethod();
1017 } else { 1117 } else {
1018 ChangeInputMethod(*iter); 1118 ChangeInputMethod(*iter);
1019 } 1119 }
1020 } 1120 }
1021 1121
1122 // Handles input method specific hotkeys like XK_Henkan.
1123 void SwitchToInputMethod(HotkeyEvent event) {
1124 // Sanity check.
1125 if (active_input_method_ids_.empty()) {
1126 LOG(ERROR) << "active input method is empty";
1127 return;
1128 }
1129
1130 // Get the list of input method ids for |event_id|. For example, get
1131 // { "mozc-hangul", "xkb:kr:kr104:kor" } for kKoreanInputMethodOrLayout.
1132 const char* const* input_method_ids_to_switch = NULL;
1133 switch (event) {
1134 case kPreviousInputMethod:
1135 case kNextInputMethod:
1136 // These events should not be handled here.
1137 break;
1138 case kJapaneseInputMethod:
1139 case kJapaneseLayout:
1140 case kJapaneseInputMethodOrLayout:
1141 case kKoreanInputMethodOrLayout:
1142 for (size_t i = 0; i < kInputMethodSpecificHotkeySettingsLen; ++i) {
1143 if (event == kInputMethodSpecificHotkeySettings[i].event_id) {
1144 input_method_ids_to_switch =
1145 kInputMethodSpecificHotkeySettings[i].input_method_ids;
1146 }
1147 }
1148 break;
1149 }
1150 if (!input_method_ids_to_switch) {
1151 LOG(ERROR) << "Unknown event: " << event;
1152 return;
1153 }
1154
1155 // Obtain the intersection of input_method_ids_to_switch and
1156 // active_input_method_ids_. The order of IDs in active_input_method_ids_ is
1157 // preserved.
1158 std::vector<std::string> ids;
1159 for (size_t i = 0; i < kMaxInputMethodsPerHotkey; ++i) {
1160 const char* id = input_method_ids_to_switch[i];
1161 if (id && std::find(active_input_method_ids_.begin(),
1162 active_input_method_ids_.end(),
1163 id) != active_input_method_ids_.end()) {
1164 ids.push_back(id);
1165 }
1166 }
1167 if (ids.empty()) {
1168 LOG(ERROR) << "No input method for " << event << " is active";
1169 return;
1170 }
1171
1172 // If current_input_method_ is not in ids, switch to ids[0]. If
1173 // current_input_method_ is ids[N], switch to ids[N+1].
1174 std::vector<std::string>::const_iterator iter =
1175 std::find(ids.begin(), ids.end(), current_input_method_.id());
1176 if (iter != ids.end()) {
1177 ++iter;
1178 }
1179 if (iter == ids.end()) {
1180 iter = ids.begin();
1181 }
1182 ChangeInputMethod(*iter);
1183 }
1184
1022 // A reference to the language api, to allow callbacks when the input method 1185 // A reference to the language api, to allow callbacks when the input method
1023 // status changes. 1186 // status changes.
1024 IBusController* ibus_controller_; 1187 IBusController* ibus_controller_;
1025 ObserverList<InputMethodManager::Observer> observers_; 1188 ObserverList<InputMethodManager::Observer> observers_;
1026 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_; 1189 ObserverList<VirtualKeyboardObserver> virtual_keyboard_observers_;
1027 1190
1028 // The input method which was/is selected. 1191 // The input method which was/is selected.
1029 InputMethodDescriptor previous_input_method_; 1192 InputMethodDescriptor previous_input_method_;
1030 InputMethodDescriptor current_input_method_; 1193 InputMethodDescriptor current_input_method_;
1031 1194
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1081 // An object which keeps a list of available virtual keyboards. 1244 // An object which keeps a list of available virtual keyboards.
1082 VirtualKeyboardSelector virtual_keyboard_selector_; 1245 VirtualKeyboardSelector virtual_keyboard_selector_;
1083 1246
1084 // The active input method ids cache. 1247 // The active input method ids cache.
1085 std::vector<std::string> active_input_method_ids_; 1248 std::vector<std::string> active_input_method_ids_;
1086 1249
1087 // Extra input methods that have been explicitly added to the menu, such as 1250 // Extra input methods that have been explicitly added to the menu, such as
1088 // those created by extension. 1251 // those created by extension.
1089 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_; 1252 std::map<std::string, InputMethodDescriptor> extra_input_method_ids_;
1090 1253
1254 // A muitlmap from input method id to input method specific hotkey
1255 // information. e.g. "mozc-jp" to XK_ZenkakuHankaku, "mozc-jp" to XK_Henkan.
1256 std::multimap<std::string,
1257 const InputMethodSpecificHotkeySetting*> extra_hotkeys_;
1091 // An object which detects Control+space and Shift+Alt key presses. 1258 // An object which detects Control+space and Shift+Alt key presses.
1092 HotkeyManager hotkey_manager_; 1259 HotkeyManager hotkey_manager_;
1093 1260
1094 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl); 1261 DISALLOW_COPY_AND_ASSIGN(InputMethodManagerImpl);
1095 }; 1262 };
1096 1263
1097 // static 1264 // static
1098 InputMethodManager* InputMethodManager::GetInstance() { 1265 InputMethodManager* InputMethodManager::GetInstance() {
1099 return InputMethodManagerImpl::GetInstance(); 1266 return InputMethodManagerImpl::GetInstance();
1100 } 1267 }
1101 1268
1102 } // namespace input_method 1269 } // namespace input_method
1103 } // namespace chromeos 1270 } // namespace chromeos
1104 1271
1105 // Allows InvokeLater without adding refcounting. This class is a Singleton and 1272 // Allows InvokeLater without adding refcounting. This class is a Singleton and
1106 // won't be deleted until it's last InvokeLater is run. 1273 // won't be deleted until it's last InvokeLater is run.
1107 DISABLE_RUNNABLE_METHOD_REFCOUNT( 1274 DISABLE_RUNNABLE_METHOD_REFCOUNT(
1108 chromeos::input_method::InputMethodManagerImpl); 1275 chromeos::input_method::InputMethodManagerImpl);
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698