Index: chrome/browser/chromeos/input_method/xkeyboard.cc |
diff --git a/chrome/browser/chromeos/input_method/xkeyboard.cc b/chrome/browser/chromeos/input_method/xkeyboard.cc |
index aaf89d9ee022329b70a84a32c2a521f5c0ff1216..4aa9002e756acda15bce074297c20bd36f998aa2 100644 |
--- a/chrome/browser/chromeos/input_method/xkeyboard.cc |
+++ b/chrome/browser/chromeos/input_method/xkeyboard.cc |
@@ -96,15 +96,23 @@ const char* kCapsLockRemapped[] = { |
"xkb:us:colemak:eng", |
}; |
+// A string for obtaining a mask value for Num Lock. |
+const char kNumLockVirtualModifierString[] = "NumLock"; |
+ |
} // namespace |
XKeyboard::XKeyboard(const InputMethodUtil& util) |
: is_running_on_chrome_os_( |
system::runtime_environment::IsRunningOnChromeOS()) { |
+ num_lock_mask_ = GetNumLockMask(); |
+ GetLockedModifiers( |
+ num_lock_mask_, ¤t_caps_lock_status_, ¤t_num_lock_status_); |
+ |
for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { |
ModifierKey key = kCustomizableKeys[i]; |
current_modifier_map_.push_back(ModifierKeyPair(key, key)); |
} |
+ |
std::string layout; |
for (size_t i = 0; i < arraysize(kKeepRightAltInputMethods); ++i) { |
layout = util.GetKeyboardLayoutName(kKeepRightAltInputMethods[i]); |
@@ -127,6 +135,46 @@ XKeyboard::XKeyboard(const InputMethodUtil& util) |
XKeyboard::~XKeyboard() { |
} |
+// static |
+unsigned int XKeyboard::GetNumLockMask() { |
+ static const unsigned int kBadMask = 0; |
+ |
+ unsigned int real_mask = kBadMask; |
+ XkbDescPtr xkb_desc = |
+ XkbGetKeyboard(ui::GetXDisplay(), XkbAllComponentsMask, XkbUseCoreKbd); |
+ if (!xkb_desc) { |
+ return kBadMask; |
+ } |
+ |
+ if (xkb_desc->dpy && xkb_desc->names && xkb_desc->names->vmods) { |
+ const std::string string_to_find(kNumLockVirtualModifierString); |
+ for (size_t i = 0; i < XkbNumVirtualMods; ++i) { |
+ const unsigned int virtual_mod_mask = 1U << i; |
+ const char* virtual_mod_str = |
+ XGetAtomName(xkb_desc->dpy, xkb_desc->names->vmods[i]); |
+ if (!virtual_mod_str) { |
+ continue; |
+ } |
+ if (string_to_find == virtual_mod_str) { |
+ if (!XkbVirtualModsToReal(xkb_desc, virtual_mod_mask, &real_mask)) { |
+ LOG(ERROR) << "XkbVirtualModsToReal failed"; |
+ real_mask = kBadMask; // reset the return value, just in case. |
+ } |
+ break; |
+ } |
+ } |
+ } |
+ XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); |
+ |
+ // Some code in Chrome, e.g. web_input_event_aurax11.cc, assume that Mod2Mask |
+ // is always assigned to Num Lock. |
+ // TODO(yusukes): Check the assumption is really okay. If not, modify such |
+ // code, and then remove the CHECK below. |
+ CHECK(real_mask == Mod2Mask); |
+ |
+ return real_mask; |
+} |
+ |
bool XKeyboard::SetLayoutInternal(const std::string& layout_name, |
const ModifierMap& modifier_map, |
bool force) { |
@@ -319,19 +367,81 @@ bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { |
return true; |
} |
+void XKeyboard::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
+ ModifierLockStatus new_num_lock_status) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (!num_lock_mask_) { |
+ LOG(ERROR) << "Cannot set locked modifiers. Num Lock mask unknown."; |
+ return; |
+ } |
+ |
+ unsigned int affect_mask = 0; |
+ unsigned int value_mask = 0; |
+ if (new_caps_lock_status != kDontChange) { |
+ affect_mask |= LockMask; |
+ value_mask |= ((new_caps_lock_status == kEnableLock) ? LockMask : 0); |
+ current_caps_lock_status_ = (new_caps_lock_status == kEnableLock); |
+ } |
+ if (new_num_lock_status != kDontChange) { |
+ affect_mask |= num_lock_mask_; |
+ value_mask |= ((new_num_lock_status == kEnableLock) ? num_lock_mask_ : 0); |
+ current_num_lock_status_ = (new_num_lock_status == kEnableLock); |
+ } |
+ |
+ if (affect_mask) { |
+ XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, affect_mask, value_mask); |
+ } |
+} |
+ |
+void XKeyboard::SetNumLockEnabled(bool enable_num_lock) { |
+ SetLockedModifiers( |
+ kDontChange, enable_num_lock ? kEnableLock : kDisableLock); |
+} |
+ |
+void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { |
+ SetLockedModifiers( |
+ enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); |
+} |
+ |
// static |
-bool XKeyboard::CapsLockIsEnabled() { |
+void XKeyboard::GetLockedModifiers(unsigned int num_lock_mask, |
+ bool* out_caps_lock_enabled, |
+ bool* out_num_lock_enabled) { |
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (out_num_lock_enabled && !num_lock_mask) { |
+ LOG(ERROR) << "Cannot get locked modifiers. Num Lock mask unknown."; |
+ if (out_caps_lock_enabled) { |
+ *out_caps_lock_enabled = false; |
+ } |
+ if (out_num_lock_enabled) { |
+ *out_num_lock_enabled = false; |
+ } |
+ return; |
+ } |
+ |
XkbStateRec status; |
XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); |
- return status.locked_mods & LockMask; |
+ if (out_caps_lock_enabled) { |
+ *out_caps_lock_enabled = status.locked_mods & LockMask; |
+ } |
+ if (out_num_lock_enabled) { |
+ *out_num_lock_enabled = status.locked_mods & num_lock_mask; |
+ } |
} |
// static |
-void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- XkbLockModifiers(ui::GetXDisplay(), XkbUseCoreKbd, LockMask, |
- enable_caps_lock ? LockMask : 0); |
+bool XKeyboard::NumLockIsEnabled(unsigned int num_lock_mask) { |
+ bool num_lock_enabled = false; |
+ GetLockedModifiers(num_lock_mask, NULL /* Caps Lock */, &num_lock_enabled); |
+ return num_lock_enabled; |
+} |
+ |
+// static |
+bool XKeyboard::CapsLockIsEnabled() { |
+ bool caps_lock_enabled = false; |
+ GetLockedModifiers(0, &caps_lock_enabled, NULL /* Num Lock */); |
+ return caps_lock_enabled; |
} |
// static |
@@ -362,6 +472,11 @@ bool XKeyboard::ReapplyCurrentKeyboardLayout() { |
current_layout_name_, current_modifier_map_, true /* force */); |
} |
+void XKeyboard::ReapplyCurrentModifierLockStatus() { |
+ SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, |
+ current_num_lock_status_ ? kEnableLock : kDisableLock); |
+} |
+ |
bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { |
const std::string layout_name = current_layout_name_.empty() ? |
kDefaultLayoutName : current_layout_name_; |