1{ system ? builtins.currentSystem }:
2
3with import ../lib/testing.nix { inherit system; };
4
5let
6 readyFile = "/tmp/readerReady";
7 resultFile = "/tmp/readerResult";
8
9 testReader = pkgs.writeScript "test-input-reader" ''
10 #!${pkgs.stdenv.shell}
11 rm -f ${resultFile} ${resultFile}.tmp
12 logger "testReader: START: Waiting for $1 characters, expecting '$2'."
13 touch ${readyFile}
14 read -r -N $1 chars
15 rm -f ${readyFile}
16
17 if [ "$chars" == "$2" ]; then
18 logger -s "testReader: PASS: Got '$2' as expected." 2>${resultFile}.tmp
19 else
20 logger -s "testReader: FAIL: Expected '$2' but got '$chars'." 2>${resultFile}.tmp
21 fi
22 # rename after the file is written to prevent a race condition
23 mv ${resultFile}.tmp ${resultFile}
24 '';
25
26
27 mkKeyboardTest = layout: { extraConfig ? {}, tests }: with pkgs.lib; let
28 combinedTests = foldAttrs (acc: val: acc ++ val) [] (builtins.attrValues tests);
29 perlStr = val: "'${escape ["'" "\\"] val}'";
30 lq = length combinedTests.qwerty;
31 le = length combinedTests.expect;
32 msg = "length mismatch between qwerty (${toString lq}) and expect (${toString le}) lists!";
33 send = concatMapStringsSep ", " perlStr combinedTests.qwerty;
34 expect = if (lq == le) then concatStrings combinedTests.expect else throw msg;
35
36 in makeTest {
37 name = "keymap-${layout}";
38
39 machine.services.xserver.desktopManager.xterm.enable = false;
40 machine.i18n.consoleKeyMap = mkOverride 900 layout;
41 machine.services.xserver.layout = mkOverride 900 layout;
42 machine.imports = [ ./common/x11.nix extraConfig ];
43
44 testScript = ''
45
46 sub mkTest ($$) {
47 my ($desc, $cmd) = @_;
48
49 subtest $desc, sub {
50 # prepare and start testReader
51 $machine->execute("rm -f ${readyFile} ${resultFile}");
52 $machine->succeed("$cmd ${testReader} ${toString le} ".q(${escapeShellArg expect} & ));
53
54 if ($desc eq "Xorg keymap") {
55 # make sure the xterm window is open and has focus
56 $machine->waitForWindow(qr/testterm/);
57 $machine->waitUntilSucceeds("${pkgs.xdotool}/bin/xdotool search --sync --onlyvisible --class testterm windowfocus --sync");
58 }
59
60 # wait for reader to be ready
61 $machine->waitForFile("${readyFile}");
62 $machine->sleep(1);
63
64 # send all keys
65 foreach ((${send})) { $machine->sendKeys($_); };
66
67 # wait for result and check
68 $machine->waitForFile("${resultFile}");
69 $machine->succeed("grep -q 'PASS:' ${resultFile}");
70 };
71 };
72
73 $machine->waitForX;
74
75 mkTest "VT keymap", "openvt -sw --";
76 mkTest "Xorg keymap", "DISPLAY=:0 xterm -title testterm -class testterm -fullscreen -e";
77 '';
78 };
79
80in pkgs.lib.mapAttrs mkKeyboardTest {
81 azerty = {
82 tests = {
83 azqw.qwerty = [ "q" "w" ];
84 azqw.expect = [ "a" "z" ];
85 altgr.qwerty = [ "alt_r-2" "alt_r-3" "alt_r-4" "alt_r-5" "alt_r-6" ];
86 altgr.expect = [ "~" "#" "{" "[" "|" ];
87 };
88
89 extraConfig.i18n.consoleKeyMap = "azerty/fr";
90 extraConfig.services.xserver.layout = "fr";
91 };
92
93 colemak = {
94 tests = {
95 homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
96 homerow.expect = [ "a" "r" "s" "t" "n" "e" "i" "o" ];
97 };
98
99 extraConfig.i18n.consoleKeyMap = "en-latin9";
100 extraConfig.services.xserver.layout = "us";
101 extraConfig.services.xserver.xkbVariant = "colemak";
102 };
103
104 dvorak = {
105 tests = {
106 homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
107 homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ];
108 symbols.qwerty = [ "q" "w" "e" "minus" "equal" ];
109 symbols.expect = [ "'" "," "." "[" "]" ];
110 };
111 };
112
113 dvp = {
114 tests = {
115 homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ];
116 homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ];
117 numbers.qwerty = map (x: "shift-${x}")
118 [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ];
119 numbers.expect = [ "%" "7" "5" "3" "1" "9" "0" "2" "4" "6" "8" ];
120 symbols.qwerty = [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ];
121 symbols.expect = [ "&" "[" "{" "}" "(" "=" "*" ")" "+" "]" "!" ];
122 };
123
124 extraConfig.services.xserver.layout = "us";
125 extraConfig.services.xserver.xkbVariant = "dvp";
126 };
127
128 neo = {
129 tests = {
130 layer1.qwerty = [ "f" "j" ];
131 layer1.expect = [ "e" "n" ];
132 layer2.qwerty = [ "shift-f" "shift-j" "shift-6" ];
133 layer2.expect = [ "E" "N" "$" ];
134 layer3.qwerty = [ "caps_lock-d" "caps_lock-f" ];
135 layer3.expect = [ "{" "}" ];
136 };
137
138 extraConfig.services.xserver.layout = "de";
139 extraConfig.services.xserver.xkbVariant = "neo";
140 };
141
142 qwertz = {
143 tests = {
144 zy.qwerty = [ "z" "y" ];
145 zy.expect = [ "y" "z" ];
146 altgr.qwerty = map (x: "alt_r-${x}")
147 [ "q" "less" "7" "8" "9" "0" ];
148 altgr.expect = [ "@" "|" "{" "[" "]" "}" ];
149 };
150
151 extraConfig.i18n.consoleKeyMap = "de";
152 extraConfig.services.xserver.layout = "de";
153 };
154}