summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 06:03:59 +0000
committeryusukes@google.com <yusukes@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-09 06:03:59 +0000
commit4fa423e8a85c549895b10cd6ca7dc30a1d41ea65 (patch)
tree59953272029fc6a52f307f5846a4fe8cda2a11b1
parent81d169dd4e752fb153880d0067872c3d4584b5c1 (diff)
downloadchromium_src-4fa423e8a85c549895b10cd6ca7dc30a1d41ea65.zip
chromium_src-4fa423e8a85c549895b10cd6ca7dc30a1d41ea65.tar.gz
chromium_src-4fa423e8a85c549895b10cd6ca7dc30a1d41ea65.tar.bz2
Merge 108841 - Reapply Caps Lock and Num Lock to core keyboard whenever new X input device is added.
- Let Chrome maintain Num Lock & Caps Lock state. Monitor the X device hierarchy, and, upon detecting any newly attached keyboards, reapply the current Num Lock and Caps Lock state to the master/core keyboard, which will then propagate down to all slaves (including the newly attached one). - Similarly, whenever Chrome detects a Num Lock and/or Caps Lock state change originating from the server, it parrots the change back down to X. This fixes the XKB asymmetric indicator state propagation. See also: http://crosbug.com/p/6245#c18 BUG=chromium-os:22562 BUG=crosbug.com/p/5795 BUG=crosbug.com/p/6245 TEST=On Mario and Alex, connect a USB hub, and connect two keyboards, say A and B, to the hub. Press NumLock on A, confirm that the NumLock LED on B also changes. Do the same for CapsLock. Review URL: http://codereview.chromium.org/8356040 TBR=yusukes@chromium.org Review URL: http://codereview.chromium.org/8509001 git-svn-id: svn://svn.chromium.org/chrome/branches/912/src@109191 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/input_method/input_method_manager.h3
-rw-r--r--chrome/browser/chromeos/input_method/xkeyboard.cc127
-rw-r--r--chrome/browser/chromeos/input_method/xkeyboard.h65
-rw-r--r--chrome/browser/chromeos/input_method/xkeyboard_unittest.cc157
-rw-r--r--chrome/browser/chromeos/system_key_event_listener.cc43
-rw-r--r--chrome/browser/chromeos/system_key_event_listener.h2
-rw-r--r--chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.cc15
-rw-r--r--chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc4
8 files changed, 340 insertions, 76 deletions
diff --git a/chrome/browser/chromeos/input_method/input_method_manager.h b/chrome/browser/chromeos/input_method/input_method_manager.h
index cb929a7..8d1799e 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager.h
@@ -1,9 +1,6 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-//
-// TODO(satorux): Move this from 'cros' directory to 'input_method'
-// directory.
#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_INPUT_METHOD_MANAGER_H_
diff --git a/chrome/browser/chromeos/input_method/xkeyboard.cc b/chrome/browser/chromeos/input_method/xkeyboard.cc
index 61c8338..de80724 100644
--- a/chrome/browser/chromeos/input_method/xkeyboard.cc
+++ b/chrome/browser/chromeos/input_method/xkeyboard.cc
@@ -94,15 +94,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_, &current_caps_lock_status_, &current_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]);
@@ -125,6 +133,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) {
@@ -317,19 +365,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
@@ -360,6 +470,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_;
diff --git a/chrome/browser/chromeos/input_method/xkeyboard.h b/chrome/browser/chromeos/input_method/xkeyboard.h
index 27c6714..cbe9852 100644
--- a/chrome/browser/chromeos/input_method/xkeyboard.h
+++ b/chrome/browser/chromeos/input_method/xkeyboard.h
@@ -22,6 +22,12 @@ struct AutoRepeatRate {
unsigned int repeat_interval_in_ms;
};
+enum ModifierLockStatus {
+ kDisableLock = 0,
+ kEnableLock,
+ kDontChange,
+};
+
enum ModifierKey {
kSearchKey = 0, // Customizable.
kLeftControlKey, // Customizable.
@@ -68,6 +74,47 @@ class XKeyboard {
// xinput_hierarchy_changed_event_listener.h for details.
bool ReapplyCurrentKeyboardLayout();
+ // Updates keyboard LEDs on all keyboards.
+ // XKB asymmetrically propagates keyboard modifier indicator state changes to
+ // slave keyboards. If the state change is initiated from a client to the
+ // "core/master keyboard", XKB changes global state and pushes an indication
+ // change down to all keyboards. If the state change is initiated by one slave
+ // (physical) keyboard, it changes global state but only pushes an indicator
+ // state change down to that one keyboard.
+ // This function changes LEDs on all keyboards by explicitly updating the
+ // core/master keyboard.
+ void ReapplyCurrentModifierLockStatus();
+
+ // Sets the Caps Lock and Num Lock status. Do not call the function from
+ // non-UI threads.
+ void SetLockedModifiers(ModifierLockStatus new_caps_lock_status,
+ ModifierLockStatus new_num_lock_status);
+
+ // Sets the num lock status to |enable_num_lock|. Do not call the function
+ // from non-UI threads.
+ void SetNumLockEnabled(bool enable_num_lock);
+
+ // Sets the caps lock status to |enable_caps_lock|. Do not call the function
+ // from non-UI threads.
+ void SetCapsLockEnabled(bool enable_caps_lock);
+
+ // Set true on |out_caps_lock_enabled| if Caps Lock is enabled. Set true on
+ // |out_num_lock_enabled| if Num Lock (or to be precise, the modifier
+ // specified by |num_lock_mask|) is enabled. Both 'out' parameters can be
+ // NULL. When |out_num_lock_enabled| is NULL, |num_lock_mask| is ignored (you
+ // can pass 0 in this case). Do not call the function from non-UI threads.
+ static void GetLockedModifiers(unsigned int num_lock_mask,
+ bool* out_caps_lock_enabled,
+ bool* out_num_lock_enabled);
+
+ // Returns true if num lock is enabled. Do not call the function from non-UI
+ // threads.
+ static bool NumLockIsEnabled(unsigned int num_lock_mask);
+
+ // Returns true if caps lock is enabled. Do not call the function from non-UI
+ // threads.
+ static bool CapsLockIsEnabled();
+
// Turns on and off the auto-repeat of the keyboard. Returns true on success.
// Do not call the function from non-UI threads.
static bool SetAutoRepeatEnabled(bool enabled);
@@ -77,13 +124,8 @@ class XKeyboard {
// non-UI threads.
static bool SetAutoRepeatRate(const AutoRepeatRate& rate);
- // Returns true if caps lock is enabled. Do not call the function from non-UI
- // threads.
- static bool CapsLockIsEnabled();
-
- // Sets the caps lock status to |enable_caps_lock|. Do not call the function
- // from non-UI threads.
- static void SetCapsLockEnabled(bool enabled);
+ // Returns a mask (e.g. 1U<<4) for Num Lock. On error, returns 0.
+ static unsigned int GetNumLockMask();
protected:
// Creates a full XKB layout name like
@@ -127,18 +169,23 @@ class XKeyboard {
// Called when execve'd setxkbmap process exits.
static void OnSetLayoutFinish(pid_t pid, int status, XKeyboard* 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_;
- const bool is_running_on_chrome_os_;
-
DISALLOW_COPY_AND_ASSIGN(XKeyboard);
};
diff --git a/chrome/browser/chromeos/input_method/xkeyboard_unittest.cc b/chrome/browser/chromeos/input_method/xkeyboard_unittest.cc
index 02068dc..a1f0da5 100644
--- a/chrome/browser/chromeos/input_method/xkeyboard_unittest.cc
+++ b/chrome/browser/chromeos/input_method/xkeyboard_unittest.cc
@@ -47,16 +47,20 @@ class XKeyboardTest : public testing::Test {
XKeyboardTest()
: controller_(IBusController::Create()),
util_(controller_->GetSupportedInputMethods()),
- xkey_(util_),
ui_thread_(BrowserThread::UI, &message_loop_) {
}
- static void SetUpTestCase() {
+ virtual void SetUp() {
+ xkey_.reset(new TestableXKeyboard(util_));
+ }
+
+ virtual void TearDown() {
+ xkey_.reset();
}
scoped_ptr<IBusController> controller_;
InputMethodUtil util_;
- TestableXKeyboard xkey_;
+ scoped_ptr<TestableXKeyboard> xkey_;
MessageLoopForUI message_loop_;
BrowserThread ui_thread_;
@@ -102,127 +106,127 @@ bool DisplayAvailable() {
// Tests CreateFullXkbLayoutName() function.
TEST_F(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) {
// CreateFullXkbLayoutName should not accept an empty |layout_name|.
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName(
"", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
// CreateFullXkbLayoutName should not accept an empty ModifierMap.
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName(
"us", ModifierMap()).c_str());
// CreateFullXkbLayoutName should not accept an incomplete ModifierMap.
ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.pop_back();
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
// CreateFullXkbLayoutName should not accept redundant ModifierMaps.
tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey)); // two search maps
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey)); // two ctrls
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey)); // two alts.
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
// CreateFullXkbLayoutName should not accept invalid ModifierMaps.
tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey)); // can't remap void
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey)); // ditto
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName("us", tmp_map).c_str());
// CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock.
EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us",
GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str());
EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us",
GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str());
EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us",
GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str());
// CreateFullXkbLayoutName should not accept non-alphanumeric characters
// except "()-_".
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName(
"us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName(
"us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"ab-c_12",
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
// CreateFullXkbLayoutName should not accept upper-case ascii characters.
- EXPECT_STREQ("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STREQ("", xkey_->CreateFullXkbLayoutName(
"US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
// CreateFullXkbLayoutName should accept lower-case ascii characters.
for (int c = 'a'; c <= 'z'; ++c) {
- EXPECT_STRNE("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STRNE("", xkey_->CreateFullXkbLayoutName(
std::string(3, c),
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
}
// CreateFullXkbLayoutName should accept numbers.
for (int c = '0'; c <= '9'; ++c) {
- EXPECT_STRNE("", xkey_.CreateFullXkbLayoutName(
+ EXPECT_STRNE("", xkey_->CreateFullXkbLayoutName(
std::string(3, c),
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
}
// CreateFullXkbLayoutName should accept a layout with a variant name.
EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us(dvorak)",
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
EXPECT_STREQ("jp+chromeos(disabled_disabled_disabled),us",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"jp", // does not use AltGr, therefore no _keepralt.
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
// When the layout name is not "us", the second layout should be added.
- EXPECT_EQ(std::string::npos, xkey_.CreateFullXkbLayoutName(
+ EXPECT_EQ(std::string::npos, xkey_->CreateFullXkbLayoutName(
"us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
- EXPECT_EQ(std::string::npos, xkey_.CreateFullXkbLayoutName(
+ EXPECT_EQ(std::string::npos, xkey_->CreateFullXkbLayoutName(
"us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
- EXPECT_NE(std::string::npos, xkey_.CreateFullXkbLayoutName(
+ EXPECT_NE(std::string::npos, xkey_->CreateFullXkbLayoutName(
"gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
- EXPECT_NE(std::string::npos, xkey_.CreateFullXkbLayoutName(
+ EXPECT_NE(std::string::npos, xkey_->CreateFullXkbLayoutName(
"jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
}
TEST_F(XKeyboardTest, TestCreateFullXkbLayoutNameKeepCapsLock) {
EXPECT_STREQ("us(colemak)+chromeos(search_disabled_disabled)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us(colemak)",
// The 1st kVoidKey should be ignored.
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
EXPECT_STREQ("de(neo)+"
"chromeos(search_leftcontrol_leftcontrol_keepralt),us",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
// The 1st kLeftControlKey should be ignored.
"de(neo)", GetMap(kLeftControlKey,
kLeftControlKey,
kLeftControlKey)).c_str());
EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled_keepralt),us",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"gb(extd)",
GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
}
TEST_F(XKeyboardTest, TestCreateFullXkbLayoutNameKeepAlt) {
EXPECT_STREQ("us(intl)+chromeos(disabled_disabled_disabled_keepralt)",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"us(intl)", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
EXPECT_STREQ("kr(kr104)+"
"chromeos(leftcontrol_leftcontrol_leftcontrol_keepralt),us",
- xkey_.CreateFullXkbLayoutName(
+ xkey_->CreateFullXkbLayoutName(
"kr(kr104)", GetMap(kLeftControlKey,
kLeftControlKey,
kLeftControlKey)).c_str());
@@ -235,7 +239,7 @@ TEST_F(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) {
for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) {
for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) {
- const std::string layout = xkey_.CreateFullXkbLayoutName(
+ const std::string layout = xkey_->CreateFullXkbLayoutName(
"us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k)));
// CreateFullXkbLayoutName should succeed (i.e. should not return "".)
EXPECT_STREQ("us+", layout.substr(0, 3).c_str())
@@ -247,20 +251,87 @@ TEST_F(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
}
}
-TEST_F(XKeyboardTest, TestSetCapsLockIsEnabled) {
+TEST_F(XKeyboardTest, TestSetCapsLockEnabled) {
+ if (!DisplayAvailable()) {
+ return;
+ }
+ const bool initial_lock_state = xkey_->CapsLockIsEnabled();
+ xkey_->SetCapsLockEnabled(true);
+ EXPECT_TRUE(TestableXKeyboard::CapsLockIsEnabled());
+ xkey_->SetCapsLockEnabled(false);
+ EXPECT_FALSE(TestableXKeyboard::CapsLockIsEnabled());
+ xkey_->SetCapsLockEnabled(true);
+ EXPECT_TRUE(TestableXKeyboard::CapsLockIsEnabled());
+ xkey_->SetCapsLockEnabled(false);
+ EXPECT_FALSE(TestableXKeyboard::CapsLockIsEnabled());
+ xkey_->SetCapsLockEnabled(initial_lock_state);
+}
+
+TEST_F(XKeyboardTest, TestSetNumLockEnabled) {
+ if (!DisplayAvailable()) {
+ return;
+ }
+ const unsigned int num_lock_mask = TestableXKeyboard::GetNumLockMask();
+ ASSERT_NE(0U, num_lock_mask);
+
+ const bool initial_lock_state = xkey_->NumLockIsEnabled(num_lock_mask);
+ xkey_->SetNumLockEnabled(true);
+ EXPECT_TRUE(TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+ xkey_->SetNumLockEnabled(false);
+ EXPECT_FALSE(TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+ xkey_->SetNumLockEnabled(true);
+ EXPECT_TRUE(TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+ xkey_->SetNumLockEnabled(false);
+ EXPECT_FALSE(TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+ xkey_->SetNumLockEnabled(initial_lock_state);
+}
+
+TEST_F(XKeyboardTest, TestSetCapsLockAndNumLockAtTheSameTime) {
if (!DisplayAvailable()) {
return;
}
- const bool initial_lock_state = XKeyboard::CapsLockIsEnabled();
- XKeyboard::SetCapsLockEnabled(true);
- EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
- XKeyboard::SetCapsLockEnabled(false);
- EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
- XKeyboard::SetCapsLockEnabled(true);
- EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
- XKeyboard::SetCapsLockEnabled(false);
- EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
- XKeyboard::SetCapsLockEnabled(initial_lock_state);
+ const unsigned int num_lock_mask = TestableXKeyboard::GetNumLockMask();
+ ASSERT_NE(0U, num_lock_mask);
+
+ const bool initial_caps_lock_state = xkey_->CapsLockIsEnabled();
+ const bool initial_num_lock_state = xkey_->NumLockIsEnabled(num_lock_mask);
+
+ // Flip both.
+ xkey_->SetLockedModifiers(
+ initial_caps_lock_state ? kDisableLock : kEnableLock,
+ initial_num_lock_state ? kDisableLock : kEnableLock);
+ EXPECT_EQ(!initial_caps_lock_state,
+ TestableXKeyboard::CapsLockIsEnabled());
+ EXPECT_EQ(!initial_num_lock_state,
+ TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+
+ // Flip Caps Lock.
+ xkey_->SetLockedModifiers(
+ initial_caps_lock_state ? kEnableLock : kDisableLock,
+ kDontChange);
+ // Use GetLockedModifiers() for verifying the result.
+ bool c, n;
+ TestableXKeyboard::GetLockedModifiers(num_lock_mask, &c, &n);
+ EXPECT_EQ(initial_caps_lock_state, c);
+ EXPECT_EQ(!initial_num_lock_state, n);
+
+ // Flip Num Lock to restore the initial state.
+ xkey_->SetLockedModifiers(
+ kDontChange,
+ initial_caps_lock_state ? kEnableLock : kDisableLock);
+ TestableXKeyboard::GetLockedModifiers(num_lock_mask, &c, &n);
+ EXPECT_EQ(initial_caps_lock_state, c);
+ EXPECT_EQ(initial_num_lock_state, n);
+
+ // No-op SetLockedModifiers call.
+ xkey_->SetLockedModifiers(kDontChange, kDontChange);
+ EXPECT_EQ(initial_caps_lock_state,
+ TestableXKeyboard::CapsLockIsEnabled());
+ EXPECT_EQ(initial_num_lock_state,
+ TestableXKeyboard::NumLockIsEnabled(num_lock_mask));
+
+ // No-op GetLockedModifiers call. Confirm it does not crash.
+ TestableXKeyboard::GetLockedModifiers(0, NULL, NULL);
}
TEST_F(XKeyboardTest, TestContainsModifierKeyAsReplacement) {
diff --git a/chrome/browser/chromeos/system_key_event_listener.cc b/chrome/browser/chromeos/system_key_event_listener.cc
index df24857..9cc461a4 100644
--- a/chrome/browser/chromeos/system_key_event_listener.cc
+++ b/chrome/browser/chromeos/system_key_event_listener.cc
@@ -67,8 +67,11 @@ SystemKeyEventListener* SystemKeyEventListener::GetInstance() {
SystemKeyEventListener::SystemKeyEventListener()
: stopped_(false),
- caps_lock_is_on_(input_method::XKeyboard::CapsLockIsEnabled()),
+ num_lock_mask_(input_method::XKeyboard::GetNumLockMask()),
xkb_event_base_(0) {
+ input_method::XKeyboard::GetLockedModifiers(
+ num_lock_mask_, &caps_lock_is_on_, &num_lock_is_on_);
+
Display* display = ui::GetXDisplay();
key_brightness_down_ = XKeysymToKeycode(display,
XF86XK_MonBrightnessDown);
@@ -177,16 +180,15 @@ GdkFilterReturn SystemKeyEventListener::GdkEventFilter(GdkXEvent* gxevent,
#endif // defined(TOUCH_UI) || !defined(TOOLKIT_USES_GTK)
void SystemKeyEventListener::GrabKey(int32 key, uint32 mask) {
- uint32 num_lock_mask = Mod2Mask;
uint32 caps_lock_mask = LockMask;
Display* display = ui::GetXDisplay();
Window root = DefaultRootWindow(display);
XGrabKey(display, key, mask, root, True, GrabModeAsync, GrabModeAsync);
XGrabKey(display, key, mask | caps_lock_mask, root, True,
GrabModeAsync, GrabModeAsync);
- XGrabKey(display, key, mask | num_lock_mask, root, True,
+ XGrabKey(display, key, mask | num_lock_mask_, root, True,
GrabModeAsync, GrabModeAsync);
- XGrabKey(display, key, mask | caps_lock_mask | num_lock_mask, root,
+ XGrabKey(display, key, mask | caps_lock_mask | num_lock_mask_, root,
True, GrabModeAsync, GrabModeAsync);
}
@@ -269,11 +271,14 @@ void SystemKeyEventListener::ShowVolumeBubble() {
}
bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
+ input_method::InputMethodManager* input_method_manager =
+ input_method::InputMethodManager::GetInstance();
+
if (xevent->type == KeyPress || xevent->type == KeyRelease) {
// Change the current keyboard layout (or input method) if xevent is one of
// the input method hotkeys.
input_method::HotkeyManager* hotkey_manager =
- input_method::InputMethodManager::GetInstance()->GetHotkeyManager();
+ input_method_manager->GetHotkeyManager();
if (hotkey_manager->FilterKeyEvent(*xevent)) {
return true;
}
@@ -282,11 +287,30 @@ bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
if (xevent->type == xkb_event_base_) {
XkbEvent* xkey_event = reinterpret_cast<XkbEvent*>(xevent);
if (xkey_event->any.xkb_type == XkbStateNotify) {
- const bool new_lock_state = (xkey_event->state.locked_mods) & LockMask;
- if (caps_lock_is_on_ != new_lock_state) {
- caps_lock_is_on_ = new_lock_state;
+ input_method::ModifierLockStatus new_caps_lock_state =
+ input_method::kDontChange;
+ input_method::ModifierLockStatus new_num_lock_state =
+ input_method::kDontChange;
+
+ bool enabled = (xkey_event->state.locked_mods) & LockMask;
+ if (caps_lock_is_on_ != enabled) {
+ caps_lock_is_on_ = enabled;
+ new_caps_lock_state =
+ enabled ? input_method::kEnableLock : input_method::kDisableLock;
OnCapsLock(caps_lock_is_on_);
}
+
+ enabled = (xkey_event->state.locked_mods) & num_lock_mask_;
+ if (num_lock_is_on_ != enabled) {
+ num_lock_is_on_ = enabled;
+ new_num_lock_state =
+ enabled ? input_method::kEnableLock : input_method::kDisableLock;
+ }
+
+ // Propagate the keyboard LED change to _ALL_ keyboards
+ input_method_manager->GetXKeyboard()->SetLockedModifiers(
+ new_caps_lock_state, new_num_lock_state);
+
return true;
}
} else if (xevent->type == KeyPress) {
@@ -298,7 +322,8 @@ bool SystemKeyEventListener::ProcessedXEvent(XEvent* xevent) {
const bool other_mods_are_held =
(xevent->xkey.state & ~(ShiftMask | LockMask));
if (other_shift_is_held && !other_mods_are_held)
- input_method::XKeyboard::SetCapsLockEnabled(!caps_lock_is_on_);
+ input_method_manager->GetXKeyboard()->SetCapsLockEnabled(
+ !caps_lock_is_on_);
}
// Only doing non-Alt/Shift/Ctrl modified keys
diff --git a/chrome/browser/chromeos/system_key_event_listener.h b/chrome/browser/chromeos/system_key_event_listener.h
index 2930dfc..d63924f 100644
--- a/chrome/browser/chromeos/system_key_event_listener.h
+++ b/chrome/browser/chromeos/system_key_event_listener.h
@@ -100,6 +100,8 @@ class SystemKeyEventListener : public MessageLoopForUI::Observer {
bool stopped_;
+ const unsigned int num_lock_mask_;
+ bool num_lock_is_on_;
bool caps_lock_is_on_;
ObserverList<CapsLockObserver> caps_lock_observers_;
diff --git a/chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.cc b/chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.cc
index 1d381a3..a3960dc 100644
--- a/chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.cc
+++ b/chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.cc
@@ -45,13 +45,18 @@ void SelectXInputEvents() {
// Checks the |event| and asynchronously sets the XKB layout when necessary.
void HandleHierarchyChangedEvent(XIHierarchyEvent* event) {
+ if (!(event->flags & XISlaveAdded)) {
+ return;
+ }
for (int i = 0; i < event->num_info; ++i) {
XIHierarchyInfo* info = &event->info[i];
- if ((event->flags & XISlaveAdded) &&
- (info->use == XIFloatingSlave) &&
- (info->flags & XISlaveAdded)) {
- chromeos::input_method::InputMethodManager::GetInstance()->
- GetXKeyboard()->ReapplyCurrentKeyboardLayout();
+ if ((info->flags & XISlaveAdded) && (info->use == XIFloatingSlave)) {
+ chromeos::input_method::InputMethodManager* input_method_manager =
+ chromeos::input_method::InputMethodManager::GetInstance();
+ chromeos::input_method::XKeyboard* xkeyboard =
+ input_method_manager->GetXKeyboard();
+ xkeyboard->ReapplyCurrentModifierLockStatus();
+ xkeyboard->ReapplyCurrentKeyboardLayout();
break;
}
}
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index ebcfb89..d139130d 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -17,6 +17,7 @@
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/network_library.h"
#include "chrome/browser/chromeos/cros/power_library.h"
+#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/xkeyboard.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/webui_login_display.h"
@@ -301,7 +302,8 @@ void SigninScreenHandler::Show(bool oobe_ui) {
SendUserList(false);
// Reset Caps Lock state when login screen is shown.
- input_method::XKeyboard::SetCapsLockEnabled(false);
+ input_method::InputMethodManager::GetInstance()->GetXKeyboard()->
+ SetCapsLockEnabled(false);
ShowScreen(kAccountPickerScreen, NULL);
}