Home | History | Annotate | Download | only in input_method
      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