{ system ? builtins.currentSystem }: with import ../lib/testing.nix { inherit system; }; let testReader = pkgs.writeScript "test-input-reader" '' #!${pkgs.stdenv.shell} readInput() { touch /tmp/reader.ready echo "Waiting for '$1' to be typed" read -r -n1 c if [ "$c" = "$2" ]; then echo "SUCCESS: Got back '$c' as expected." echo 0 >&2 else echo "FAIL: Expected '$2' but got '$c' instead." echo 1 >&2 fi } main() { error=0 while [ $# -gt 0 ]; do ret="$((readInput "$2" "$3" | systemd-cat -t "$1") 2>&1)" if [ $ret -ne 0 ]; then error=1; fi shift 3 done return $error } main "$@"; echo -n $? > /tmp/reader.exit ''; mkReaderInput = testname: { qwerty, expect }: with pkgs.lib; let lq = length qwerty; le = length expect; msg = "`qwerty' (${lq}) and `expect' (${le}) lists" + " need to be of the same length!"; result = flatten (zipListsWith (a: b: [testname a b]) qwerty expect); in if lq != le then throw msg else result; mkKeyboardTest = layout: { extraConfig ? {}, tests }: with pkgs.lib; let readerInput = flatten (mapAttrsToList mkReaderInput tests); perlStr = val: "'${escape ["'" "\\"] val}'"; perlReaderInput = concatMapStringsSep ", " perlStr readerInput; in makeTest { name = "keymap-${layout}"; machine.services.xserver.desktopManager.xterm.enable = false; machine.i18n.consoleKeyMap = mkOverride 900 layout; machine.services.xserver.layout = mkOverride 900 layout; machine.imports = [ ./common/x11.nix extraConfig ]; machine.services.xserver.displayManager.slim = { enable = true; # Use a custom theme in order to get best OCR results theme = pkgs.runCommand "slim-theme-ocr" { nativeBuildInputs = [ pkgs.imagemagick ]; } '' mkdir "$out" convert -size 1x1 xc:white "$out/background.jpg" convert -size 200x100 xc:white "$out/panel.jpg" cat > "$out/slim.theme" <succeed( "for i in \$(seq 600); do if [ -e '$_[0]' ]; then ". "cat '$_[0]' && rm -f '$_[0]' && exit 0; ". "fi; sleep 0.1; done; echo timed out after 60 seconds >&2; exit 1" ); }; sub mkTest ($$) { my ($desc, $cmd) = @_; my @testdata = (${perlReaderInput}); my $shellTestdata = join ' ', map { "'".s/'/'\\'''/gr."'" } @testdata; subtest $desc, sub { $machine->succeed("$cmd ${testReader} $shellTestdata &"); while (my ($testname, $qwerty, $expect) = splice(@testdata, 0, 3)) { waitCatAndDelete "/tmp/reader.ready"; $machine->sendKeys($qwerty); }; my $exitcode = waitCatAndDelete "/tmp/reader.exit"; die "tests for $desc failed" if $exitcode ne 0; }; } $machine->waitForX; mkTest "VT keymap", "openvt -sw --"; mkTest "Xorg keymap", "DISPLAY=:0 xterm -fullscreen -e"; ''; }; in pkgs.lib.mapAttrs mkKeyboardTest { azerty = { tests = { azqw.qwerty = [ "q" "w" ]; azqw.expect = [ "a" "z" ]; altgr.qwerty = [ "alt_r-2" "alt_r-3" "alt_r-4" "alt_r-5" "alt_r-6" ]; altgr.expect = [ "~" "#" "{" "[" "|" ]; }; extraConfig.i18n.consoleKeyMap = "azerty/fr"; extraConfig.services.xserver.layout = "fr"; }; colemak = { tests = { homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; homerow.expect = [ "a" "r" "s" "t" "n" "e" "i" "o" ]; }; extraConfig.i18n.consoleKeyMap = "en-latin9"; extraConfig.services.xserver.layout = "us"; extraConfig.services.xserver.xkbVariant = "colemak"; }; dvorak = { tests = { homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ]; symbols.qwerty = [ "q" "w" "e" "minus" "equal" ]; symbols.expect = [ "'" "," "." "[" "]" ]; }; }; dvp = { tests = { homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ]; numbers.qwerty = map (x: "shift-${x}") [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ]; numbers.expect = [ "%" "7" "5" "3" "1" "9" "0" "2" "4" "6" "8" ]; symbols.qwerty = [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ]; symbols.expect = [ "&" "[" "{" "}" "(" "=" "*" ")" "+" "]" "!" ]; }; extraConfig.services.xserver.layout = "us"; extraConfig.services.xserver.xkbVariant = "dvp"; }; neo = { tests = { layer1.qwerty = [ "f" "j" ]; layer1.expect = [ "e" "n" ]; layer2.qwerty = [ "shift-f" "shift-j" "shift-6" ]; layer2.expect = [ "E" "N" "$" ]; layer3.qwerty = [ "caps_lock-d" "caps_lock-f" ]; layer3.expect = [ "{" "}" ]; }; extraConfig.services.xserver.layout = "de"; extraConfig.services.xserver.xkbVariant = "neo"; }; qwertz = { tests = { zy.qwerty = [ "z" "y" ]; zy.expect = [ "y" "z" ]; altgr.qwerty = map (x: "alt_r-${x}") [ "q" "less" "7" "8" "9" "0" ]; altgr.expect = [ "@" "|" "{" "[" "]" "}" ]; }; extraConfig.i18n.consoleKeyMap = "de"; extraConfig.services.xserver.layout = "de"; }; }