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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/input_method/xkeyboard.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <string> 10 11 #include <gtest/gtest.h> 12 #include <X11/Xlib.h> 13 14 #include "base/logging.h" 15 16 namespace chromeos { 17 namespace input_method { 18 19 namespace { 20 21 // Returns a ModifierMap object that contains the following mapping: 22 // - kSearchKey is mapped to |search|. 23 // - kLeftControl key is mapped to |control|. 24 // - kLeftAlt key is mapped to |alt|. 25 ModifierMap GetMap(ModifierKey search, ModifierKey control, ModifierKey alt) { 26 ModifierMap modifier_key; 27 // Use the Search key as |search|. 28 modifier_key.push_back(ModifierKeyPair(kSearchKey, search)); 29 modifier_key.push_back(ModifierKeyPair(kLeftControlKey, control)); 30 modifier_key.push_back(ModifierKeyPair(kLeftAltKey, alt)); 31 return modifier_key; 32 } 33 34 // Checks |modifier_map| and returns true if the following conditions are met: 35 // - kSearchKey is mapped to |search|. 36 // - kLeftControl key is mapped to |control|. 37 // - kLeftAlt key is mapped to |alt|. 38 bool CheckMap(const ModifierMap& modifier_map, 39 ModifierKey search, ModifierKey control, ModifierKey alt) { 40 ModifierMap::const_iterator begin = modifier_map.begin(); 41 ModifierMap::const_iterator end = modifier_map.end(); 42 if ((std::count(begin, end, ModifierKeyPair(kSearchKey, search)) == 1) && 43 (std::count(begin, end, 44 ModifierKeyPair(kLeftControlKey, control)) == 1) && 45 (std::count(begin, end, ModifierKeyPair(kLeftAltKey, alt)) == 1)) { 46 return true; 47 } 48 return false; 49 } 50 51 // Returns true if X display is available. 52 bool DisplayAvailable() { 53 Display* display = XOpenDisplay(NULL); 54 if (!display) { 55 return false; 56 } 57 XCloseDisplay(display); 58 return true; 59 } 60 61 } // namespace 62 63 // Tests CreateFullXkbLayoutName() function. 64 TEST(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) { 65 // CreateFullXkbLayoutName should not accept an empty |layout_name|. 66 EXPECT_STREQ("", CreateFullXkbLayoutName( 67 "", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 68 69 // CreateFullXkbLayoutName should not accept an empty ModifierMap. 70 EXPECT_STREQ("", CreateFullXkbLayoutName("us", ModifierMap()).c_str()); 71 72 // CreateFullXkbLayoutName should not accept an incomplete ModifierMap. 73 ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 74 tmp_map.pop_back(); 75 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 76 77 // CreateFullXkbLayoutName should not accept redundant ModifierMaps. 78 tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 79 tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey)); // two search maps 80 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 81 tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 82 tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey)); // two ctrls 83 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 84 tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 85 tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey)); // two alts. 86 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 87 88 // CreateFullXkbLayoutName should not accept invalid ModifierMaps. 89 tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 90 tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey)); // can't remap void 91 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 92 tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey); 93 tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey)); // ditto 94 EXPECT_STREQ("", CreateFullXkbLayoutName("us", tmp_map).c_str()); 95 96 // CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock. 97 EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)", 98 CreateFullXkbLayoutName( 99 "us", 100 GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str()); 101 EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)", 102 CreateFullXkbLayoutName( 103 "us", 104 GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str()); 105 EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)", 106 CreateFullXkbLayoutName( 107 "us", 108 GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str()); 109 110 // CreateFullXkbLayoutName should not accept non-alphanumeric characters 111 // except "()-_". 112 EXPECT_STREQ("", CreateFullXkbLayoutName( 113 "us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 114 EXPECT_STREQ("", CreateFullXkbLayoutName( 115 "us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 116 EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us", 117 CreateFullXkbLayoutName( 118 "ab-c_12", 119 GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 120 121 // CreateFullXkbLayoutName should not accept upper-case ascii characters. 122 EXPECT_STREQ("", CreateFullXkbLayoutName( 123 "US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 124 125 // CreateFullXkbLayoutName should accept lower-case ascii characters. 126 for (int c = 'a'; c <= 'z'; ++c) { 127 EXPECT_STRNE("", CreateFullXkbLayoutName( 128 std::string(3, c), 129 GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 130 } 131 132 // CreateFullXkbLayoutName should accept numbers. 133 for (int c = '0'; c <= '9'; ++c) { 134 EXPECT_STRNE("", CreateFullXkbLayoutName( 135 std::string(3, c), 136 GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 137 } 138 139 // CreateFullXkbLayoutName should accept a layout with a variant name. 140 EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)", 141 CreateFullXkbLayoutName( 142 "us(dvorak)", 143 GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 144 // TODO: Re-enable this when the stub is fixed to handle it. 145 // EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled),us", 146 // CreateFullXkbLayoutName( 147 // "gb(extd)", 148 // GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str()); 149 EXPECT_STREQ("gb(extd)+", CreateFullXkbLayoutName( 150 "gb(extd)", 151 GetMap(kVoidKey, kVoidKey, kVoidKey)).substr(0, 9).c_str()); 152 EXPECT_STREQ("jp+", CreateFullXkbLayoutName( 153 "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).substr(0, 3).c_str()); 154 155 // When the layout name is not "us", the second layout should be added. 156 EXPECT_EQ(std::string::npos, CreateFullXkbLayoutName( 157 "us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us")); 158 EXPECT_EQ(std::string::npos, CreateFullXkbLayoutName( 159 "us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us")); 160 EXPECT_NE(std::string::npos, CreateFullXkbLayoutName( 161 "gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us")); 162 EXPECT_NE(std::string::npos, CreateFullXkbLayoutName( 163 "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us")); 164 } 165 166 // Tests if CreateFullXkbLayoutName and ExtractLayoutNameFromFullXkbLayoutName 167 // functions could handle all combinations of modifier remapping. 168 TEST(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) { 169 std::set<std::string> layouts; 170 for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) { 171 for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) { 172 for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) { 173 const std::string layout = CreateFullXkbLayoutName( 174 "us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k))); 175 // CreateFullXkbLayoutName should succeed (i.e. should not return "".) 176 EXPECT_STREQ("us+", layout.substr(0, 3).c_str()) 177 << "layout: " << layout; 178 // All 4*3*3 layouts should be different. 179 EXPECT_TRUE(layouts.insert(layout).second) << "layout: " << layout; 180 } 181 } 182 } 183 } 184 185 TEST(XKeyboardTest, TestSetCapsLockIsEnabled) { 186 if (!DisplayAvailable()) { 187 return; 188 } 189 const bool initial_lock_state = CapsLockIsEnabled(); 190 SetCapsLockEnabled(true); 191 EXPECT_TRUE(CapsLockIsEnabled()); 192 SetCapsLockEnabled(false); 193 EXPECT_FALSE(CapsLockIsEnabled()); 194 SetCapsLockEnabled(true); 195 EXPECT_TRUE(CapsLockIsEnabled()); 196 SetCapsLockEnabled(false); 197 EXPECT_FALSE(CapsLockIsEnabled()); 198 SetCapsLockEnabled(initial_lock_state); 199 } 200 201 TEST(XKeyboardTest, TestContainsModifierKeyAsReplacement) { 202 EXPECT_FALSE(ContainsModifierKeyAsReplacement( 203 GetMap(kVoidKey, kVoidKey, kVoidKey), kCapsLockKey)); 204 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 205 GetMap(kCapsLockKey, kVoidKey, kVoidKey), kCapsLockKey)); 206 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 207 GetMap(kVoidKey, kCapsLockKey, kVoidKey), kCapsLockKey)); 208 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 209 GetMap(kVoidKey, kVoidKey, kCapsLockKey), kCapsLockKey)); 210 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 211 GetMap(kCapsLockKey, kCapsLockKey, kVoidKey), kCapsLockKey)); 212 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 213 GetMap(kCapsLockKey, kCapsLockKey, kCapsLockKey), kCapsLockKey)); 214 EXPECT_TRUE(ContainsModifierKeyAsReplacement( 215 GetMap(kSearchKey, kVoidKey, kVoidKey), kSearchKey)); 216 } 217 218 } // namespace input_method 219 } // namespace chromeos 220