diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml
index 798d1fbdfd85..7cdc5196e0d2 100644
--- a/nixos/doc/manual/configuration/x-windows.xml
+++ b/nixos/doc/manual/configuration/x-windows.xml
@@ -125,10 +125,12 @@
You will need to reboot after enabling this driver to prevent a clash with
other kernel modules.
+
- Note: for recent AMD GPUs you most likely want to keep either the defaults
+ For recent AMD GPUs you most likely want to keep either the defaults
or "amdgpu" (both free).
+ Touchpads
@@ -157,4 +159,134 @@
versions.
+
+ Custom XKB layouts
+
+ It is possible to install custom
+
+ XKB
+
+ keyboard layouts using the option
+ .
+ As a first example, we are going to create a layout based on the basic US
+ layout, with an additional layer to type some greek symbols by pressing the
+ right-alt key.
+
+
+ To do this we are going to create a us-greek file
+ with a xkb_symbols section.
+
+
+xkb_symbols "us-greek"
+{
+ include "us(basic)" // includes the base US keys
+ include "level3(ralt_switch)" // configures right alt as a third level switch
+
+ key <LatA> { [ a, A, Greek_alpha ] };
+ key <LatB> { [ b, B, Greek_beta ] };
+ key <LatG> { [ g, G, Greek_gamma ] };
+ key <LatD> { [ d, D, Greek_delta ] };
+ key <LatZ> { [ z, Z, Greek_zeta ] };
+};
+
+
+ To install the layout, the filepath, a description and the list of
+ languages must be given:
+
+
+.us-greek = {
+ description = "US layout with alt-gr greek";
+ languages = [ "eng" ];
+ symbolsFile = /path/to/us-greek;
+}
+
+
+
+ The name should match the one given to the
+ xkb_symbols block.
+
+
+
+ The layout should now be installed and ready to use: try it by
+ running setxkbmap us-greek and type
+ <alt>+a. To change the default the usual
+
+ option can still be used.
+
+
+ A layout can have several other components besides
+ xkb_symbols, for example we will define new
+ keycodes for some multimedia key and bind these to some symbol.
+
+
+ Use the xev utility from
+ pkgs.xorg.xev to find the codes of the keys of
+ interest, then create a media-key file to hold
+ the keycodes definitions
+
+
+xkb_keycodes "media"
+{
+ <volUp> = 123;
+ <volDown> = 456;
+}
+
+
+ Now use the newly define keycodes in media-sym:
+
+
+xkb_symbols "media"
+{
+ key.type = "ONE_LEVEL";
+ key <volUp> { [ XF86AudioLowerVolume ] };
+ key <volDown> { [ XF86AudioRaiseVolume ] };
+}
+
+
+ As before, to install the layout do
+
+
+.media = {
+ description = "Multimedia keys remapping";
+ languages = [ "eng" ];
+ symbolsFile = /path/to/media-key;
+ keycodesFile = /path/to/media-sym;
+};
+
+
+
+ The function pkgs.writeText <filename> <content>
+ can be useful if you prefer to keep the layout definitions
+ inside the NixOS configuration.
+
+
+
+ Unfortunately, the Xorg server does not (currently) support setting a
+ keymap directly but relies instead on XKB rules to select the matching
+ components (keycodes, types, ...) of a layout. This means that components
+ other than symbols won't be loaded by default. As a workaround, you
+ can set the keymap using setxkbmap at the start of the
+ session with:
+
+
+ = "setxkbmap -keycodes media";
+
+
+ To learn how to write layouts take a look at the XKB
+
+ documentation
+ . More example layouts can also be found
+
+ here
+ .
+
+
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 8d63a03dd057..8c6bc47df251 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -815,6 +815,7 @@
./services/web-servers/uwsgi.nix
./services/web-servers/varnish/default.nix
./services/web-servers/zope2.nix
+ ./services/x11/extra-layouts.nix
./services/x11/colord.nix
./services/x11/compton.nix
./services/x11/unclutter.nix
diff --git a/nixos/modules/services/x11/extra-layouts.nix b/nixos/modules/services/x11/extra-layouts.nix
new file mode 100644
index 000000000000..5523dd2bf023
--- /dev/null
+++ b/nixos/modules/services/x11/extra-layouts.nix
@@ -0,0 +1,165 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ layouts = config.services.xserver.extraLayouts;
+
+ layoutOpts = {
+ options = {
+ description = mkOption {
+ type = types.str;
+ description = "A short description of the layout.";
+ };
+
+ languages = mkOption {
+ type = types.listOf types.str;
+ description =
+ ''
+ A list of languages provided by the layout.
+ (Use ISO 639-2 codes, for example: "eng" for english)
+ '';
+ };
+
+ compatFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the xkb compat file.
+ This file sets the compatibility state, used to preserve
+ compatibility with xkb-unaware programs.
+ It must contain a xkb_compat "name" { ... } block.
+ '';
+ };
+
+ geometryFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the xkb geometry file.
+ This (completely optional) file describes the physical layout of
+ keyboard, which maybe be used by programs to depict it.
+ It must contain a xkb_geometry "name" { ... } block.
+ '';
+ };
+
+ keycodesFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the xkb keycodes file.
+ This file specifies the range and the interpretation of the raw
+ keycodes sent by the keyboard.
+ It must contain a xkb_keycodes "name" { ... } block.
+ '';
+ };
+
+ symbolsFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the xkb symbols file.
+ This is the most important file: it defines which symbol or action
+ maps to each key and must contain a
+ xkb_symbols "name" { ... } block.
+ '';
+ };
+
+ typesFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ The path to the xkb types file.
+ This file specifies the key types that can be associated with
+ the various keyboard keys.
+ It must contain a xkb_types "name" { ... } block.
+ '';
+ };
+
+ };
+ };
+
+in
+
+{
+
+ ###### interface
+
+ options.services.xserver = {
+ extraLayouts = mkOption {
+ type = types.attrsOf (types.submodule layoutOpts);
+ default = {};
+ example = literalExample
+ ''
+ {
+ mine = {
+ description = "My custom xkb layout.";
+ languages = [ "eng" ];
+ symbolsFile = /path/to/my/layout;
+ };
+ }
+ '';
+ description = ''
+ Extra custom layouts that will be included in the xkb configuration.
+ Information on how to create a new layout can be found here:
+ .
+ For more examples see
+
+ '';
+ };
+
+ };
+
+ ###### implementation
+
+ config = mkIf (layouts != { }) {
+
+ # We don't override xkeyboard_config directly to
+ # reduce the amount of packages to be recompiled.
+ # Only the following packages are necessary to set
+ # a custom layout anyway:
+ nixpkgs.overlays = lib.singleton (self: super: {
+
+ xkb_patched = self.xorg.xkeyboardconfig_custom {
+ layouts = config.services.xserver.extraLayouts;
+ };
+
+ xorg = super.xorg // {
+ xorgserver = super.xorg.xorgserver.overrideAttrs (old: {
+ configureFlags = old.configureFlags ++ [
+ "--with-xkb-bin-directory=${self.xorg.xkbcomp}/bin"
+ "--with-xkb-path=${self.xkb_patched}/share/X11/xkb"
+ ];
+ });
+
+ setxkbmap = super.xorg.setxkbmap.overrideAttrs (old: {
+ postInstall =
+ ''
+ mkdir -p $out/share
+ ln -sfn ${self.xkb_patched}/etc/X11 $out/share/X11
+ '';
+ });
+
+ xkbcomp = super.xorg.xkbcomp.overrideAttrs (old: {
+ configureFlags = "--with-xkb-config-root=${self.xkb_patched}/share/X11/xkb";
+ });
+
+ };
+
+ ckbcomp = super.ckbcomp.override {
+ xkeyboard_config = self.xkb_patched;
+ };
+
+ xkbvalidate = super.xkbvalidate.override {
+ libxkbcommon = self.libxkbcommon.override {
+ xkeyboard_config = self.xkb_patched;
+ };
+ };
+
+ });
+
+ services.xserver.xkbDir = "${pkgs.xkb_patched}/etc/X11/xkb";
+
+ };
+
+}
diff --git a/pkgs/servers/x11/xorg/overrides.nix b/pkgs/servers/x11/xorg/overrides.nix
index 1da5c31c25f6..80b0addd6ec8 100644
--- a/pkgs/servers/x11/xorg/overrides.nix
+++ b/pkgs/servers/x11/xorg/overrides.nix
@@ -1,7 +1,7 @@
{ abiCompat ? null,
stdenv, makeWrapper, fetchurl, fetchpatch, buildPackages,
automake, autoconf, gettext, libiconv, libtool, intltool,
- freetype, tradcpp, fontconfig, meson, ninja,
+ freetype, tradcpp, fontconfig, meson, ninja, ed,
libGL, spice-protocol, zlib, libGLU, dbus, libunwind, libdrm,
mesa, udev, bootstrap_cmds, bison, flex, clangStdenv, autoreconfHook,
mcpp, epoxy, openssl, pkgconfig, llvm_6,
@@ -423,6 +423,85 @@ self: super:
'';
});
+ # xkeyboardconfig variant extensible with custom layouts.
+ # See nixos/modules/services/x11/extra-layouts.nix
+ xkeyboardconfig_custom = { layouts ? { } }:
+ let
+ patchIn = name: layout:
+ with layout;
+ with lib;
+ ''
+ # install layout files
+ ${optionalString (compatFile != null) "cp '${compatFile}' 'compat/${name}'"}
+ ${optionalString (geometryFile != null) "cp '${geometryFile}' 'geometry/${name}'"}
+ ${optionalString (keycodesFile != null) "cp '${keycodesFile}' 'keycodes/${name}'"}
+ ${optionalString (symbolsFile != null) "cp '${symbolsFile}' 'symbols/${name}'"}
+ ${optionalString (typesFile != null) "cp '${typesFile}' 'types/${name}'"}
+
+ # patch makefiles
+ for type in compat geometry keycodes symbols types; do
+ if ! test -f "$type/${name}"; then
+ continue
+ fi
+ test "$type" = geometry && type_name=geom || type_name=$type
+ ${ed}/bin/ed -v $type/Makefile.am <
+ -
+ a
+
+
+ ${name}
+ <_description>${layout.description}
+ ${layout.description}
+
+
+ .
+ w
+ EOF
+
+ # add layout description
+ ${ed}/bin/ed -v rules/base.xml <
+ -
+ a
+
+
+ ${name}
+ <_shortDescription>${name}
+ <_description>${layout.description}
+
+ ${concatMapStrings (lang: "${lang}\n") layout.languages}
+
+
+
+
+ .
+ w
+ EOF
+ '';
+ in
+ self.xkeyboardconfig.overrideAttrs (old: {
+ buildInputs = old.buildInputs ++ [ automake ];
+ postPatch = with lib; concatStrings (mapAttrsToList patchIn layouts);
+ });
+
xload = super.xload.overrideAttrs (attrs: {
nativeBuildInputs = attrs.nativeBuildInputs ++ [ gettext ];
});