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/xkeyboard.h" | 5 #include "chrome/browser/chromeos/input_method/xkeyboard.h" |
6 | 6 |
7 #include <queue> | 7 #include <queue> |
8 #include <set> | 8 #include <set> |
9 #include <string> | 9 #include <string> |
10 #include <utility> | 10 #include <utility> |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 "xkb:us:altgr-intl:eng", | 89 "xkb:us:altgr-intl:eng", |
90 "xkb:us:intl:eng", | 90 "xkb:us:intl:eng", |
91 }; | 91 }; |
92 | 92 |
93 // These are the overlay names with caps lock remapped | 93 // These are the overlay names with caps lock remapped |
94 const char* kCapsLockRemapped[] = { | 94 const char* kCapsLockRemapped[] = { |
95 "xkb:de:neo:ger", | 95 "xkb:de:neo:ger", |
96 "xkb:us:colemak:eng", | 96 "xkb:us:colemak:eng", |
97 }; | 97 }; |
98 | 98 |
| 99 // A string for obtaining a mask value for Num Lock. |
| 100 const char kNumLockVirtualModifierString[] = "NumLock"; |
| 101 |
99 } // namespace | 102 } // namespace |
100 | 103 |
101 XKeyboard::XKeyboard(const InputMethodUtil& util) | 104 XKeyboard::XKeyboard(const InputMethodUtil& util) |
102 : is_running_on_chrome_os_( | 105 : is_running_on_chrome_os_( |
103 system::runtime_environment::IsRunningOnChromeOS()) { | 106 system::runtime_environment::IsRunningOnChromeOS()) { |
| 107 num_lock_mask_ = GetNumLockMask(); |
| 108 GetLockedModifiers( |
| 109 num_lock_mask_, ¤t_caps_lock_status_, ¤t_num_lock_status_); |
| 110 |
104 for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { | 111 for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { |
105 ModifierKey key = kCustomizableKeys[i]; | 112 ModifierKey key = kCustomizableKeys[i]; |
106 current_modifier_map_.push_back(ModifierKeyPair(key, key)); | 113 current_modifier_map_.push_back(ModifierKeyPair(key, key)); |
107 } | 114 } |
| 115 |
108 std::string layout; | 116 std::string layout; |
109 for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { | 117 for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { |
110 layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); | 118 layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); |
111 // The empty check is necessary since TOUCH_UI build does not support some | 119 // The empty check is necessary since TOUCH_UI build does not support some |
112 // of the kKeepRightAltInputMethods elements. For example, when TOUCH_UI is | 120 // of the kKeepRightAltInputMethods elements. For example, when TOUCH_UI is |
113 // defined, util.GetKeyboardLayoutName("xkb:us:intl:eng") would return "". | 121 // defined, util.GetKeyboardLayoutName("xkb:us:intl:eng") would return "". |
114 if (!layout.empty()) { | 122 if (!layout.empty()) { |
115 keep_right_alt_xkb_layout_names_.insert(layout); | 123 keep_right_alt_xkb_layout_names_.insert(layout); |
116 } | 124 } |
117 } | 125 } |
118 for (size_t i = 0; i < arraysize(kCapsLockRemapped); ++i) { | 126 for (size_t i = 0; i < arraysize(kCapsLockRemapped); ++i) { |
119 layout = util.GetKeyboardLayoutName(kCapsLockRemapped[i]); | 127 layout = util.GetKeyboardLayoutName(kCapsLockRemapped[i]); |
120 // The empty check is for TOUCH_UI build. See above. | 128 // The empty check is for TOUCH_UI build. See above. |
121 if (!layout.empty()) { | 129 if (!layout.empty()) { |
122 caps_lock_remapped_xkb_layout_names_.insert(layout); | 130 caps_lock_remapped_xkb_layout_names_.insert(layout); |
123 } | 131 } |
124 } | 132 } |
125 } | 133 } |
126 | 134 |
127 XKeyboard::~XKeyboard() { | 135 XKeyboard::~XKeyboard() { |
128 } | 136 } |
129 | 137 |
| 138 // static |
| 139 unsigned int XKeyboard::GetNumLockMask() { |
| 140 static const unsigned int kBadMask = 0; |
| 141 |
| 142 unsigned int real_mask = kBadMask; |
| 143 XkbDescPtr xkb_desc = |
| 144 XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); |
| 145 if (!xkb_desc) { |
| 146 return kBadMask; |
| 147 } |
| 148 |
| 149 if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { |
| 150 const std::string string_to_find(kNumLockVirtualModifierString); |
| 151 for (size_t i = 0; i < XkbNumVirtualMods; ++i) { |
| 152 const unsigned int virtual_mod_mask = 1U << i; |
| 153 const char* virtual_mod_str = |
| 154 XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); |
| 155 if (!virtual_mod_str) { |
| 156 continue; |
| 157 } |
| 158 if (string_to_find == virtual_mod_str) { |
| 159 if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { |
| 160 LOG(ERROR) << "XkbVirtualModsToReal failed"; |
| 161 real_mask = kBadMask; // reset the return value, just in case. |
| 162 } |
| 163 break; |
| 164 } |
| 165 } |
| 166 } |
| 167 XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); |
| 168 |
| 169 // Some code in Chrome, e.g. web_input_event_aurax11.cc, assume that Mod2Mask |
| 170 // is always assigned to Num Lock. |
| 171 // TODO(yusukes): Check the assumption is really okay. If not, modify such |
| 172 // code, and then remove the CHECK below. |
| 173 CHECK(real_mask == Mod2Mask); |
| 174 |
| 175 return real_mask; |
| 176 } |
| 177 |
130 bool XKeyboard::SetLayoutInternal(const std::string& layout_name, | 178 bool XKeyboard::SetLayoutInternal(const std::string& layout_name, |
131 const ModifierMap& modifier_map, | 179 const ModifierMap& modifier_map, |
132 bool force) { | 180 bool force) { |
133 if (!is_running_on_chrome_os_) { | 181 if (!is_running_on_chrome_os_) { |
134 // We should not try to change a layout on Linux or inside ui_tests. Just | 182 // We should not try to change a layout on Linux or inside ui_tests. Just |
135 // return true. | 183 // return true. |
136 return true; | 184 return true; |
137 } | 185 } |
138 | 186 |
139 const std::string layout_to_set = CreateFullXkbLayoutName( | 187 const std::string layout_to_set = CreateFullXkbLayoutName( |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 << rate.repeat_interval_in_ms << " ms interval"; | 360 << rate.repeat_interval_in_ms << " ms interval"; |
313 if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, | 361 if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
314 rate.initial_delay_in_ms, | 362 rate.initial_delay_in_ms, |
315 rate.repeat_interval_in_ms) != True) { | 363 rate.repeat_interval_in_ms) != True) { |
316 LOG(ERROR) << "Failed to set auto-repeat rate"; | 364 LOG(ERROR) << "Failed to set auto-repeat rate"; |
317 return false; | 365 return false; |
318 } | 366 } |
319 return true; | 367 return true; |
320 } | 368 } |
321 | 369 |
| 370 void XKeyboard::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
| 371 ModifierLockStatus new_num_lock_status) { |
| 372 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 373 if (!num_lock_mask_) { |
| 374 LOG(ERROR) << "Cannot set locked modifiers. Num Lock mask unknown."; |
| 375 return; |
| 376 } |
| 377 |
| 378 unsigned int affect_mask = 0; |
| 379 unsigned int value_mask = 0; |
| 380 if (new_caps_lock_status != kDontChange) { |
| 381 affect_mask |= LockMask; |
| 382 value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); |
| 383 current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); |
| 384 } |
| 385 if (new_num_lock_status != kDontChange) { |
| 386 affect_mask |= num_lock_mask_; |
| 387 value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); |
| 388 current_num_lock_status_ = (new_num_lock_status == kEnableLock); |
| 389 } |
| 390 |
| 391 if (affect_mask) { |
| 392 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); |
| 393 } |
| 394 } |
| 395 |
| 396 void XKeyboard::SetNumLockEnabled(bool enable_num_lock) { |
| 397 SetLockedModifiers( |
| 398 kDontChange, enable_num_lock ? kEnableLock : kDisableLock); |
| 399 } |
| 400 |
| 401 void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { |
| 402 SetLockedModifiers( |
| 403 enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); |
| 404 } |
| 405 |
| 406 // static |
| 407 void XKeyboard::GetLockedModifiers(unsigned int num_lock_mask, |
| 408 bool* out_caps_lock_enabled, |
| 409 bool* out_num_lock_enabled) { |
| 410 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 411 |
| 412 if (out_num_lock_enabled && !num_lock_mask) { |
| 413 LOG(ERROR) << "Cannot get locked modifiers. Num Lock mask unknown."; |
| 414 if (out_caps_lock_enabled) { |
| 415 *out_caps_lock_enabled = false; |
| 416 } |
| 417 if (out_num_lock_enabled) { |
| 418 *out_num_lock_enabled = false; |
| 419 } |
| 420 return; |
| 421 } |
| 422 |
| 423 XkbStateRec status; |
| 424 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); |
| 425 if (out_caps_lock_enabled) { |
| 426 *out_caps_lock_enabled = status.locked_mods & LockMask; |
| 427 } |
| 428 if (out_num_lock_enabled) { |
| 429 *out_num_lock_enabled = status.locked_mods & num_lock_mask; |
| 430 } |
| 431 } |
| 432 |
| 433 // static |
| 434 bool XKeyboard::NumLockIsEnabled(unsigned int num_lock_mask) { |
| 435 bool num_lock_enabled = false; |
| 436 GetLockedModifiers(num_lock_mask, NULL /* Caps Lock */, &num_lock_enabled); |
| 437 return num_lock_enabled; |
| 438 } |
| 439 |
322 // static | 440 // static |
323 bool XKeyboard::CapsLockIsEnabled() { | 441 bool XKeyboard::CapsLockIsEnabled() { |
324 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 442 bool caps_lock_enabled = false; |
325 XkbStateRec status; | 443 GetLockedModifiers(0, &caps_lock_enabled, NULL /* Num Lock */); |
326 XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); | 444 return caps_lock_enabled; |
327 return status.locked_mods & LockMask; | |
328 } | 445 } |
329 | 446 |
330 // static | 447 // static |
331 void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { | |
332 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
333 XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, LockMask, | |
334 enable_caps_lock ? LockMask : 0); | |
335 } | |
336 | |
337 // static | |
338 bool XKeyboard::ContainsModifierKeyAsReplacement( | 448 bool XKeyboard::ContainsModifierKeyAsReplacement( |
339 const ModifierMap& modifier_map, ModifierKey key) { | 449 const ModifierMap& modifier_map, ModifierKey key) { |
340 for (size_t i = 0; i < modifier_map.size(); ++i) { | 450 for (size_t i = 0; i < modifier_map.size(); ++i) { |
341 if (modifier_map[i].replacement == key) { | 451 if (modifier_map[i].replacement == key) { |
342 return true; | 452 return true; |
343 } | 453 } |
344 } | 454 } |
345 return false; | 455 return false; |
346 } | 456 } |
347 | 457 |
348 bool XKeyboard::SetCurrentKeyboardLayoutByName(const std::string& layout_name) { | 458 bool XKeyboard::SetCurrentKeyboardLayoutByName(const std::string& layout_name) { |
349 if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { | 459 if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { |
350 current_layout_name_ = layout_name; | 460 current_layout_name_ = layout_name; |
351 return true; | 461 return true; |
352 } | 462 } |
353 return false; | 463 return false; |
354 } | 464 } |
355 | 465 |
356 bool XKeyboard::ReapplyCurrentKeyboardLayout() { | 466 bool XKeyboard::ReapplyCurrentKeyboardLayout() { |
357 if (current_layout_name_.empty()) { | 467 if (current_layout_name_.empty()) { |
358 LOG(ERROR) << "Can't reapply XKB layout: layout unknown"; | 468 LOG(ERROR) << "Can't reapply XKB layout: layout unknown"; |
359 return false; | 469 return false; |
360 } | 470 } |
361 return SetLayoutInternal( | 471 return SetLayoutInternal( |
362 current_layout_name_, current_modifier_map_, true /* force */); | 472 current_layout_name_, current_modifier_map_, true /* force */); |
363 } | 473 } |
364 | 474 |
| 475 void XKeyboard::ReapplyCurrentModifierLockStatus() { |
| 476 SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, |
| 477 current_num_lock_status_ ? kEnableLock : kDisableLock); |
| 478 } |
| 479 |
365 bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { | 480 bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { |
366 const std::string layout_name = current_layout_name_.empty() ? | 481 const std::string layout_name = current_layout_name_.empty() ? |
367 kDefaultLayoutName : current_layout_name_; | 482 kDefaultLayoutName : current_layout_name_; |
368 if (SetLayoutInternal(layout_name, modifier_map, false)) { | 483 if (SetLayoutInternal(layout_name, modifier_map, false)) { |
369 current_layout_name_ = layout_name; | 484 current_layout_name_ = layout_name; |
370 current_modifier_map_ = modifier_map; | 485 current_modifier_map_ = modifier_map; |
371 return true; | 486 return true; |
372 } | 487 } |
373 return false; | 488 return false; |
374 } | 489 } |
(...skipping 20 matching lines...) Expand all Loading... |
395 case kCapsLockKey: | 510 case kCapsLockKey: |
396 return "capslock"; | 511 return "capslock"; |
397 case kNumModifierKeys: | 512 case kNumModifierKeys: |
398 break; | 513 break; |
399 } | 514 } |
400 return ""; | 515 return ""; |
401 } | 516 } |
402 | 517 |
403 } // namespace input_method | 518 } // namespace input_method |
404 } // namespace chromeos | 519 } // namespace chromeos |
OLD | NEW |