• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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|.
GetMap(ModifierKey search,ModifierKey control,ModifierKey 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|.
CheckMap(const ModifierMap & modifier_map,ModifierKey search,ModifierKey control,ModifierKey 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.
DisplayAvailable()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.
TEST(XKeyboardTest,TestCreateFullXkbLayoutNameBasic)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.
TEST(XKeyboardTest,TestCreateFullXkbLayoutNameModifierKeys)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 
TEST(XKeyboardTest,TestSetCapsLockIsEnabled)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 
TEST(XKeyboardTest,TestContainsModifierKeyAsReplacement)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