plasma-manager/modules/input.nix
Heitor Augusto f843f4258e
Some checks are pending
GitHub Pages / publish (ubuntu-latest) (push) Waiting to run
Add more keyboard options (#310)
Switching Policy, Model, Options and Layout variant
2024-08-11 12:57:44 -03:00

494 lines
14 KiB
Nix

{ config, lib, ... }:
with lib;
let
cfg = config.programs.plasma;
numlockSettings = [ "on" "off" "unchanged" ];
switchModes = [ "global" "desktop" "winClass" "window" ];
scrollMethods = {
twoFingers = 1;
touchPadEdges = 2;
};
rightClickMethods = {
bottomRight = 1;
twoFingers = 2;
};
capitalizeWord = word:
let
firstLetter = builtins.substring 0 1 word;
rest = builtins.substring 1 (builtins.stringLength word - 1) word;
in
"${toUpper firstLetter}${rest}";
layoutType = types.submodule {
options = {
layout = mkOption {
type = types.str;
example = "us";
description = ''
Keyboard layout.
'';
};
variant = mkOption {
type = with types; nullOr str;
default = null;
example = "eng";
description = ''
Keyboard layout variant.
'';
apply = builtins.toString;
};
};
};
touchPadType = types.submodule {
options = {
enable = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables or disables the touchpad.
'';
};
name = mkOption {
type = types.str;
default = null;
example = "PNP0C50:00 0911:5288 Touchpad";
description = ''
The name of the touchpad.
This can be found by looking at the Name attribute in the section in
/proc/bus/input/devices belonging to the touchpad.
'';
};
vendorId = mkOption {
type = types.str;
default = null;
example = "0911";
description = ''
The vendor ID of the touchpad.
This can be found by looking at the Vendor attribute in the section in
/proc/bus/input/devices belonging to the touchpad.
'';
};
productId = mkOption {
type = types.str;
default = null;
example = "5288";
description = ''
The product ID of the touchpad.
This can be found by looking at the Product attribute in the section
in /proc/bus/input/devices belonging to the touchpad.
'';
};
disableWhileTyping = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Disables the touchpad while typing.
'';
};
leftHanded = mkOption {
type = with types; nullOr bool;
default = null;
example = false;
description = ''
Swap the left and right buttons.
'';
};
middleButtonEmulation = mkOption {
type = with types; nullOr bool;
default = null;
example = false;
description = ''
Middle click by pressing the left and right buttons at the same time.
Activating this increases the click latency by 50ms.
'';
};
pointerSpeed = mkOption {
type = with types; nullOr (numbers.between (-1) 1);
default = null;
example = "0";
description = ''
How fast the pointer moves.
'';
};
naturalScroll = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables natural scrolling for the touchpad.
'';
};
tapToClick = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables tap-to-click for the touchpad.
'';
};
tapAndDrag = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables tap-and-drag for the touchpad.
'';
};
tapDragLock = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables tap-and-drag lock for the touchpad.
'';
};
scrollMethod = mkOption {
type = with types; nullOr (enum (builtins.attrNames scrollMethods));
default = null;
example = "touchPadEdges";
description = ''
How scrolling is performed on the touchpad.
'';
apply = method: if (method == null) then null else scrollMethods."${method}";
};
rightClickMethod = mkOption {
type = with types; nullOr (enum (builtins.attrNames rightClickMethods));
default = null;
example = "twoFingers";
description = ''
How right-clicking is performed on the touchpad.
'';
apply = method: if (method == null) then null else rightClickMethods."${method}";
};
twoFingerTap = mkOption {
type = with types; nullOr (enum [ "rightClick" "middleClick" ]);
default = null;
example = "twoFingers";
description = ''
How right-clicking is performed on the touchpad.
'';
apply = v: if (v == null) then null else (v == "middleClick");
};
};
};
touchPadToConfig = touchpad:
let
touchName = touchpad.name;
touchVendor = builtins.toString (lib.fromHexString touchpad.vendorId);
touchProduct = builtins.toString (lib.fromHexString touchpad.productId);
in
{
"Libinput/${touchVendor}/${touchProduct}/${lib.escape ["/"] touchName}" = {
Enabled = touchpad.enable;
DisableWhileTyping = touchpad.disableWhileTyping;
LeftHanded = touchpad.leftHanded;
MiddleButtonEmulation = touchpad.middleButtonEmulation;
PointerAcceleration = touchpad.pointerSpeed;
NaturalScroll = touchpad.naturalScroll;
TapToClick = touchpad.tapToClick;
TapAndDrag = touchpad.tapAndDrag;
TapDragLock = touchpad.tapDragLock;
ScrollMethod = touchpad.scrollMethod;
ClickMethod = touchpad.rightClickMethod;
LmrTapButtonMap = touchpad.twoFingerTap;
};
};
mouseType = types.submodule {
options = {
enable = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables or disables the mouse.
'';
};
name = mkOption {
type = types.str;
default = null;
example = "Logitech G403 HERO Gaming Mouse";
description = ''
The name of the mouse.
This can be found by looking at the Name attribute in the section in
/proc/bus/input/devices belonging to the mouse.
'';
};
vendorId = mkOption {
type = types.str;
default = null;
example = "046d";
description = ''
The vendor ID of the mouse.
This can be found by looking at the Vendor attribute in the section in
/proc/bus/input/devices belonging to the mouse.
'';
};
productId = mkOption {
type = types.str;
default = null;
example = "c077";
description = ''
The product ID of the mouse.
This can be found by looking at the Product attribute in the section in
/proc/bus/input/devices belonging to the mouse.
'';
};
leftHanded = mkOption {
type = with types; nullOr bool;
default = null;
example = false;
description = ''
Swap the left and right buttons.
'';
};
middleButtonEmulation = mkOption {
type = with types; nullOr bool;
default = null;
example = false;
description = ''
Middle click by pressing the left and right buttons at the same time.
Activating this increases the click latency by 50ms.
'';
};
acceleration = mkOption {
type = with types; nullOr (numbers.between (-1) 1);
default = null;
example = 0.5;
description = ''
Mouse acceleration.
'';
};
accelerationProfile = mkOption {
type = with types; nullOr (enum [ "none" "default" ]);
default = null;
example = "none";
description = "Mouse acceleration profile.";
apply = profile: if profile == "none" then 1 else if profile == "default" then 2 else null;
};
naturalScroll = mkOption {
type = with types; nullOr bool;
default = null;
example = true;
description = ''
Enables natural scrolling for the mouse.
'';
};
scrollSpeed = mkOption {
type = with types; nullOr (numbers.between 0.1 20);
default = null;
example = 1;
description = ''
How fast the scroll wheel moves.
'';
};
};
};
mouseToConfig = mouse:
let
mouseName = mouse.name;
mouseVendor = builtins.toString (lib.fromHexString mouse.vendorId);
mouseProduct = builtins.toString (lib.fromHexString mouse.productId);
in
{
"Libinput/${mouseVendor}/${mouseProduct}/${mouseName}" = {
Enabled = mouse.enable;
LeftHanded = mouse.leftHanded;
MiddleButtonEmulation = mouse.middleButtonEmulation;
NaturalScroll = mouse.naturalScroll;
PointerAcceleration = mouse.acceleration;
PointerAccelerationProfile = mouse.accelerationProfile;
ScrollFactor = mouse.scrollSpeed;
};
};
in
{
config.assertions = [
(
let
validChars = [ "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f" ];
hexChars = hexStr: builtins.tail (lib.reverseList (builtins.tail (lib.splitString "" hexStr)));
hexCodeInvalid = hex: !(lib.all (c: builtins.elem (lib.toLower c) validChars) (hexChars hex)) && (builtins.stringLength hex) > 0;
allHexCodes = lib.flatten ((map (t: [ t.vendorId t.productId ]) (cfg.input.touchpads ++ cfg.input.mice)));
invalidHexCodes = builtins.filter hexCodeInvalid allHexCodes;
in
{
assertion = (builtins.length invalidHexCodes) == 0;
message = "Invalid hex-code for product or vendor-ID in the input module in plasma-manager: ${builtins.head invalidHexCodes}";
}
)
];
# Keyboard options
options.programs.plasma.input.keyboard = {
model = mkOption {
type = with types; nullOr str;
default = null;
example = "pc104";
description = ''
Keyboard model.
'';
};
switchingPolicy = mkOption {
type = with types; nullOr (enum switchModes);
default = null;
example = "global";
description = ''
Switching policy for keyboard layouts.
'';
apply = policy: if policy == null then null else capitalizeWord policy;
};
layouts = mkOption {
type = with types; nullOr (listOf layoutType);
default = null;
example = [
{ layout = "us"; }
{ layout = "ca"; variant = "eng"; }
];
description = ''
Keyboard layouts to use.
'';
};
numlockOnStartup = mkOption {
type = with types; nullOr (enum numlockSettings);
default = null;
example = "on";
description = ''
Numpad settings at startup.
'';
};
repeatDelay = mkOption {
type = with types; nullOr (ints.between 100 5000);
default = null;
example = 200;
description = ''
How many milliseconds you need to hold a key down before the input
starts repeating.
'';
};
repeatRate = mkOption {
type = with types; nullOr (numbers.between 0.20 100.0);
default = null;
example = 50.0;
description = ''
How quick the inputs should be repeated when holding down a key.
'';
};
options = mkOption {
type = with types; nullOr (listOf str);
default = null;
example = [ "altwin:meta_alt" "caps:shift" "custom:types" ];
description = ''
Keyboard options.
'';
};
};
config.programs.plasma.configFile."kxkbrc" = mkIf (cfg.enable) (
mkMerge [
(
mkIf (cfg.input.keyboard.layouts != null) {
Layout = {
Use.value = true;
LayoutList.value = strings.concatStringsSep "," (map (l: l.layout) cfg.input.keyboard.layouts);
VariantList.value = strings.concatStringsSep "," (map (l: l.variant) cfg.input.keyboard.layouts);
};
}
)
(
mkIf (cfg.input.keyboard.options != null) {
Layout = {
ResetOldOptions.value = true;
Options.value = strings.concatStringsSep "," cfg.input.keyboard.options;
};
}
)
(
mkIf (cfg.input.keyboard.model != null) {
Layout = {
Model.value = cfg.input.keyboard.model;
};
}
)
(
mkIf (cfg.input.keyboard.switchingPolicy != null) {
Layout = {
SwitchMode.value = cfg.input.keyboard.switchingPolicy;
};
}
)
]
);
# Touchpads options
options.programs.plasma.input.touchpads = mkOption {
type = with types; listOf touchPadType;
default = [ ];
example = [
{
enable = true;
name = "PNP0C50:00 0911:5288 Touchpad";
vendorId = "2321";
productId = "21128";
disableWhileTyping = true;
leftHanded = true;
middleMouseEmulation = true;
pointerSpeed = 0;
naturalScroll = true;
tapToClick = true;
}
];
description = ''
Configure the different touchpads.
'';
};
options.programs.plasma.input.mice = mkOption {
type = with types; listOf mouseType;
default = [ ];
example = [
{
enable = true;
name = "Logitech G403 HERO Gaming Mouse";
vendorId = "046d";
productId = "c08f";
leftHanded = false;
middleButtonEmulation = false;
acceleration = 0.5;
accelerationProfile = "none";
naturalScroll = false;
scrollSpeed = 1;
}
];
description = ''
Configure the different mice.
'';
};
config.programs.plasma.configFile."kcminputrc" = mkIf (cfg.enable) (mkMerge [
{
Keyboard = (lib.filterAttrs (k: v: v != null) {
NumLock = (lists.findFirstIndex (x: x == cfg.input.keyboard.numlockOnStartup) null numlockSettings);
RepeatDelay = cfg.input.keyboard.repeatDelay;
RepeatRate = cfg.input.keyboard.repeatRate;
});
}
(mkMerge (map touchPadToConfig cfg.input.touchpads))
(mkMerge (map mouseToConfig cfg.input.mice))
]
);
}