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 2f1d3db9d22635ff6a0786d7a733be831fc3246e..29593da4bd76103c87a69cccc9df811305ff1b31 100644 |
--- a/chrome/browser/chromeos/input_method/xkeyboard.cc |
+++ b/chrome/browser/chromeos/input_method/xkeyboard.cc |
@@ -4,14 +4,12 @@ |
#include "chrome/browser/chromeos/input_method/xkeyboard.h" |
+#include <cstdlib> |
+#include <cstring> |
#include <queue> |
#include <set> |
-#include <string> |
#include <utility> |
-#include <stdlib.h> |
-#include <string.h> |
- |
#include "base/logging.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/process_util.h" |
@@ -101,9 +99,80 @@ const char* kCapsLockRemapped[] = { |
// A string for obtaining a mask value for Num Lock. |
const char kNumLockVirtualModifierString[] = "NumLock"; |
-} // namespace |
+class XKeyboardImpl : public XKeyboard { |
+ public: |
+ explicit XKeyboardImpl(const InputMethodUtil& util); |
+ virtual ~XKeyboardImpl() {} |
+ |
+ // Overridden from XKeyboard: |
+ virtual bool SetCurrentKeyboardLayoutByName( |
+ const std::string& layout_name) OVERRIDE; |
+ virtual bool RemapModifierKeys(const ModifierMap& modifier_map) OVERRIDE; |
+ virtual bool ReapplyCurrentKeyboardLayout() OVERRIDE; |
+ virtual void ReapplyCurrentModifierLockStatus() OVERRIDE; |
+ virtual void SetLockedModifiers( |
+ ModifierLockStatus new_caps_lock_status, |
+ ModifierLockStatus new_num_lock_status) OVERRIDE; |
+ virtual void SetNumLockEnabled(bool enable_num_lock) OVERRIDE; |
+ virtual void SetCapsLockEnabled(bool enable_caps_lock) OVERRIDE; |
+ virtual bool NumLockIsEnabled() OVERRIDE; |
+ virtual bool CapsLockIsEnabled() OVERRIDE; |
+ virtual unsigned int GetNumLockMask() OVERRIDE; |
+ virtual void GetLockedModifiers(bool* out_caps_lock_enabled, |
+ bool* out_num_lock_enabled) OVERRIDE; |
+ virtual std::string CreateFullXkbLayoutName( |
+ const std::string& layout_name, |
+ const ModifierMap& modifire_map) OVERRIDE; |
+ |
+ private: |
+ // This function is used by SetLayout() and RemapModifierKeys(). Calls |
+ // setxkbmap command if needed, and updates the last_full_layout_name_ cache. |
+ bool SetLayoutInternal(const std::string& layout_name, |
+ const ModifierMap& modifier_map, |
+ bool force); |
+ |
+ // Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
+ // in the |execute_queue_|. Do nothing if the queue is empty. |
+ // TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
+ void MaybeExecuteSetLayoutCommand(); |
+ |
+ // Returns true if the XKB layout uses the right Alt key for special purposes |
+ // like AltGr. |
+ bool KeepRightAlt(const std::string& xkb_layout_name) const; |
+ |
+ // Returns true if the XKB layout uses the CapsLock key for special purposes. |
+ // For example, since US Colemak layout uses the key as back space, |
+ // KeepCapsLock("us(colemak)") would return true. |
+ bool KeepCapsLock(const std::string& xkb_layout_name) const; |
+ |
+ // Converts |key| to a modifier key name which is used in |
+ // /usr/share/X11/xkb/symbols/chromeos. |
+ static std::string ModifierKeyToString(ModifierKey key); |
+ |
+ // Called when execve'd setxkbmap process exits. |
+ static void OnSetLayoutFinish(pid_t pid, int status, XKeyboardImpl* self); |
+ |
+ const bool is_running_on_chrome_os_; |
+ unsigned int num_lock_mask_; |
+ |
+ // The current Num Lock and Caps Lock status. If true, enabled. |
+ bool current_num_lock_status_; |
+ bool current_caps_lock_status_; |
+ // The XKB layout name which we set last time like "us" and "us(dvorak)". |
+ std::string current_layout_name_; |
+ // The mapping of modifier keys we set last time. |
+ ModifierMap current_modifier_map_; |
+ |
+ // A queue for executing setxkbmap one by one. |
+ std::queue<std::string> execute_queue_; |
+ |
+ std::set<std::string> keep_right_alt_xkb_layout_names_; |
+ std::set<std::string> caps_lock_remapped_xkb_layout_names_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(XKeyboardImpl); |
+}; |
-XKeyboard::XKeyboard(const InputMethodUtil& util) |
+XKeyboardImpl::XKeyboardImpl(const InputMethodUtil& util) |
: is_running_on_chrome_os_( |
system::runtime_environment::IsRunningOnChromeOS()) { |
num_lock_mask_ = GetNumLockMask(); |
@@ -116,8 +185,7 @@ XKeyboard::XKeyboard(const InputMethodUtil& util) |
CHECK(!is_running_on_chrome_os_ || (num_lock_mask_ == Mod2Mask)); |
#endif |
- GetLockedModifiers( |
- num_lock_mask_, ¤t_caps_lock_status_, ¤t_num_lock_status_); |
+ GetLockedModifiers(¤t_caps_lock_status_, ¤t_num_lock_status_); |
for (size_t i = 0; i < arraysize(kCustomizableKeys); ++i) { |
ModifierKey key = kCustomizableKeys[i]; |
@@ -144,47 +212,9 @@ 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; |
- 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. |
- } |
- XFree(virtual_mod_str); |
- break; |
- } |
- XFree(virtual_mod_str); |
- } |
- } |
- XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); |
- return real_mask; |
-} |
- |
-bool XKeyboard::SetLayoutInternal(const std::string& layout_name, |
- const ModifierMap& modifier_map, |
- bool force) { |
+bool XKeyboardImpl::SetLayoutInternal(const std::string& layout_name, |
+ const ModifierMap& modifier_map, |
+ bool force) { |
if (!is_running_on_chrome_os_) { |
// We should not try to change a layout on Linux or inside ui_tests. Just |
// return true. |
@@ -229,7 +259,7 @@ bool XKeyboard::SetLayoutInternal(const std::string& layout_name, |
// Executes 'setxkbmap -layout ...' command asynchronously using a layout name |
// in the |execute_queue_|. Do nothing if the queue is empty. |
// TODO(yusukes): Use libxkbfile.so instead of the command (crosbug.com/13105) |
-void XKeyboard::MaybeExecuteSetLayoutCommand() { |
+void XKeyboardImpl::MaybeExecuteSetLayoutCommand() { |
if (execute_queue_.empty()) { |
return; |
} |
@@ -258,21 +288,84 @@ void XKeyboard::MaybeExecuteSetLayoutCommand() { |
VLOG(1) << "ExecuteSetLayoutCommand: " << layout_to_set << ": pid=" << pid; |
} |
-// static |
-void XKeyboard::OnSetLayoutFinish(pid_t pid, int status, XKeyboard* self) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- VLOG(1) << "OnSetLayoutFinish: pid=" << pid; |
- if (self->execute_queue_.empty()) { |
- LOG(ERROR) << "OnSetLayoutFinish: execute_queue_ is empty. " |
- << "base::LaunchProcess failed? pid=" << pid; |
+bool XKeyboardImpl::NumLockIsEnabled() { |
+ bool num_lock_enabled = false; |
+ GetLockedModifiers(NULL /* Caps Lock */, &num_lock_enabled); |
+ return num_lock_enabled; |
+} |
+ |
+bool XKeyboardImpl::CapsLockIsEnabled() { |
+ bool caps_lock_enabled = false; |
+ GetLockedModifiers(&caps_lock_enabled, NULL /* Num Lock */); |
+ return caps_lock_enabled; |
+} |
+ |
+unsigned int XKeyboardImpl::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; |
+ 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. |
+ } |
+ XFree(virtual_mod_str); |
+ break; |
+ } |
+ XFree(virtual_mod_str); |
+ } |
+ } |
+ XkbFreeKeyboard(xkb_desc, 0, True /* free all components */); |
+ return real_mask; |
+} |
+ |
+void XKeyboardImpl::GetLockedModifiers(bool* out_caps_lock_enabled, |
+ bool* out_num_lock_enabled) { |
+ // For now, don't call CHECK() here to make |
+ // TabRestoreServiceTest.DontRestorePrintPreviewTab test happy. |
+ // TODO(yusukes): Fix the test, then fix the if(!BrowserThread...) line below. |
+ // CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ |
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI) || |
+ (out_num_lock_enabled && !num_lock_mask_)) { |
+ LOG(ERROR) << "Cannot get locked modifiers."; |
+ if (out_caps_lock_enabled) { |
+ *out_caps_lock_enabled = false; |
+ } |
+ if (out_num_lock_enabled) { |
+ *out_num_lock_enabled = false; |
+ } |
return; |
} |
- self->execute_queue_.pop(); |
- self->MaybeExecuteSetLayoutCommand(); |
+ |
+ XkbStateRec status; |
+ XkbGetState(ui::GetXDisplay(), XkbUseCoreKbd, &status); |
+ 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_; |
+ } |
} |
-std::string XKeyboard::CreateFullXkbLayoutName( |
- const std::string& layout_name, const ModifierMap& modifier_map) { |
+std::string XKeyboardImpl::CreateFullXkbLayoutName( |
+ const std::string& layout_name, |
+ const ModifierMap& modifier_map) { |
static const char kValidLayoutNameCharacters[] = |
"abcdefghijklmnopqrstuvwxyz0123456789()-_"; |
@@ -346,49 +439,8 @@ std::string XKeyboard::CreateFullXkbLayoutName( |
return full_xkb_layout_name; |
} |
-// static |
-bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- if (enabled) { |
- XAutoRepeatOn(ui::GetXDisplay()); |
- } else { |
- XAutoRepeatOff(ui::GetXDisplay()); |
- } |
- DLOG(INFO) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); |
- return true; |
-} |
- |
-// static |
-bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { |
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- DLOG(INFO) << "Set auto-repeat rate to: " |
- << rate.initial_delay_in_ms << " ms delay, " |
- << rate.repeat_interval_in_ms << " ms interval"; |
- if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
- rate.initial_delay_in_ms, |
- rate.repeat_interval_in_ms) != True) { |
- LOG(ERROR) << "Failed to set auto-repeat rate"; |
- return false; |
- } |
- return true; |
-} |
- |
-// static |
-bool XKeyboard::GetAutoRepeatEnabled() { |
- XKeyboardState state = {}; |
- XGetKeyboardControl(ui::GetXDisplay(), &state); |
- return state.global_auto_repeat != AutoRepeatModeOff; |
-} |
- |
-// static |
-bool XKeyboard::GetAutoRepeatRate(AutoRepeatRate* out_rate) { |
- return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
- &(out_rate->initial_delay_in_ms), |
- &(out_rate->repeat_interval_in_ms)) == True; |
-} |
- |
-void XKeyboard::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
- ModifierLockStatus new_num_lock_status) { |
+void XKeyboardImpl::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."; |
@@ -413,73 +465,18 @@ void XKeyboard::SetLockedModifiers(ModifierLockStatus new_caps_lock_status, |
} |
} |
-void XKeyboard::SetNumLockEnabled(bool enable_num_lock) { |
+void XKeyboardImpl::SetNumLockEnabled(bool enable_num_lock) { |
SetLockedModifiers( |
kDontChange, enable_num_lock ? kEnableLock : kDisableLock); |
} |
-void XKeyboard::SetCapsLockEnabled(bool enable_caps_lock) { |
+void XKeyboardImpl::SetCapsLockEnabled(bool enable_caps_lock) { |
SetLockedModifiers( |
enable_caps_lock ? kEnableLock : kDisableLock, kDontChange); |
} |
-// static |
-void XKeyboard::GetLockedModifiers(unsigned int num_lock_mask, |
- bool* out_caps_lock_enabled, |
- bool* out_num_lock_enabled) { |
- // For now, don't call CHECK() here to make |
- // TabRestoreServiceTest.DontRestorePrintPreviewTab test happy. |
- // TODO(yusukes): Fix the test, then fix the if(!BrowserThread...) line below. |
- // CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- if (!BrowserThread::CurrentlyOn(BrowserThread::UI) || |
- (out_num_lock_enabled && !num_lock_mask)) { |
- LOG(ERROR) << "Cannot get locked modifiers."; |
- 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); |
- 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 |
-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 |
-bool XKeyboard::ContainsModifierKeyAsReplacement( |
- const ModifierMap& modifier_map, ModifierKey key) { |
- for (size_t i = 0; i < modifier_map.size(); ++i) { |
- if (modifier_map[i].replacement == key) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-bool XKeyboard::SetCurrentKeyboardLayoutByName(const std::string& layout_name) { |
+bool XKeyboardImpl::SetCurrentKeyboardLayoutByName( |
+ const std::string& layout_name) { |
if (SetLayoutInternal(layout_name, current_modifier_map_, false)) { |
current_layout_name_ = layout_name; |
return true; |
@@ -487,7 +484,7 @@ bool XKeyboard::SetCurrentKeyboardLayoutByName(const std::string& layout_name) { |
return false; |
} |
-bool XKeyboard::ReapplyCurrentKeyboardLayout() { |
+bool XKeyboardImpl::ReapplyCurrentKeyboardLayout() { |
if (current_layout_name_.empty()) { |
LOG(ERROR) << "Can't reapply XKB layout: layout unknown"; |
return false; |
@@ -496,12 +493,12 @@ bool XKeyboard::ReapplyCurrentKeyboardLayout() { |
current_layout_name_, current_modifier_map_, true /* force */); |
} |
-void XKeyboard::ReapplyCurrentModifierLockStatus() { |
+void XKeyboardImpl::ReapplyCurrentModifierLockStatus() { |
SetLockedModifiers(current_caps_lock_status_ ? kEnableLock : kDisableLock, |
current_num_lock_status_ ? kEnableLock : kDisableLock); |
} |
-bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { |
+bool XKeyboardImpl::RemapModifierKeys(const ModifierMap& modifier_map) { |
const std::string layout_name = current_layout_name_.empty() ? |
kDefaultLayoutName : current_layout_name_; |
if (SetLayoutInternal(layout_name, modifier_map, false)) { |
@@ -512,16 +509,16 @@ bool XKeyboard::RemapModifierKeys(const ModifierMap& modifier_map) { |
return false; |
} |
-bool XKeyboard::KeepRightAlt(const std::string& xkb_layout_name) const { |
+bool XKeyboardImpl::KeepRightAlt(const std::string& xkb_layout_name) const { |
return keep_right_alt_xkb_layout_names_.count(xkb_layout_name) > 0; |
} |
-bool XKeyboard::KeepCapsLock(const std::string& xkb_layout_name) const { |
+bool XKeyboardImpl::KeepCapsLock(const std::string& xkb_layout_name) const { |
return caps_lock_remapped_xkb_layout_names_.count(xkb_layout_name) > 0; |
} |
// static |
-std::string XKeyboard::ModifierKeyToString(ModifierKey key) { |
+std::string XKeyboardImpl::ModifierKeyToString(ModifierKey key) { |
switch (key) { |
case kSearchKey: |
return "search"; |
@@ -539,5 +536,80 @@ std::string XKeyboard::ModifierKeyToString(ModifierKey key) { |
return ""; |
} |
+// static |
+void XKeyboardImpl::OnSetLayoutFinish(pid_t pid, |
+ int status, |
+ XKeyboardImpl* self) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ VLOG(1) << "OnSetLayoutFinish: pid=" << pid; |
+ if (self->execute_queue_.empty()) { |
+ LOG(ERROR) << "OnSetLayoutFinish: execute_queue_ is empty. " |
+ << "base::LaunchProcess failed? pid=" << pid; |
+ return; |
+ } |
+ self->execute_queue_.pop(); |
+ self->MaybeExecuteSetLayoutCommand(); |
+} |
+ |
+} // namespace |
+ |
+// static |
+bool XKeyboard::SetAutoRepeatEnabled(bool enabled) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (enabled) { |
+ XAutoRepeatOn(ui::GetXDisplay()); |
+ } else { |
+ XAutoRepeatOff(ui::GetXDisplay()); |
+ } |
+ DLOG(INFO) << "Set auto-repeat mode to: " << (enabled ? "on" : "off"); |
+ return true; |
+} |
+ |
+// static |
+bool XKeyboard::SetAutoRepeatRate(const AutoRepeatRate& rate) { |
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ DLOG(INFO) << "Set auto-repeat rate to: " |
+ << rate.initial_delay_in_ms << " ms delay, " |
+ << rate.repeat_interval_in_ms << " ms interval"; |
+ if (XkbSetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
+ rate.initial_delay_in_ms, |
+ rate.repeat_interval_in_ms) != True) { |
+ LOG(ERROR) << "Failed to set auto-repeat rate"; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+// static |
+bool XKeyboard::GetAutoRepeatEnabledForTesting() { |
+ XKeyboardState state = {}; |
+ XGetKeyboardControl(ui::GetXDisplay(), &state); |
+ return state.global_auto_repeat != AutoRepeatModeOff; |
+} |
+ |
+// static |
+bool XKeyboard::GetAutoRepeatRateForTesting(AutoRepeatRate* out_rate) { |
+ return XkbGetAutoRepeatRate(ui::GetXDisplay(), XkbUseCoreKbd, |
+ &(out_rate->initial_delay_in_ms), |
+ &(out_rate->repeat_interval_in_ms)) == True; |
+} |
+ |
+// static |
+bool XKeyboard::ContainsModifierKeyAsReplacement( |
+ const ModifierMap& modifier_map, |
+ ModifierKey key) { |
+ for (size_t i = 0; i < modifier_map.size(); ++i) { |
+ if (modifier_map[i].replacement == key) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+// static |
+XKeyboard* XKeyboard::Create(const InputMethodUtil& util) { |
+ return new XKeyboardImpl(util); |
+} |
+ |
} // namespace input_method |
} // namespace chromeos |