1{
2 config,
3 lib,
4 options,
5 pkgs,
6 ...
7}:
8
9with lib;
10
11let
12 cfg = config.services.xserver.synaptics;
13 opt = options.services.xserver.synaptics;
14 tapConfig = if cfg.tapButtons then enabledTapConfig else disabledTapConfig;
15 enabledTapConfig = ''
16 Option "MaxTapTime" "180"
17 Option "MaxTapMove" "220"
18 Option "TapButton1" "${builtins.elemAt cfg.fingersMap 0}"
19 Option "TapButton2" "${builtins.elemAt cfg.fingersMap 1}"
20 Option "TapButton3" "${builtins.elemAt cfg.fingersMap 2}"
21 '';
22 disabledTapConfig = ''
23 Option "MaxTapTime" "0"
24 Option "MaxTapMove" "0"
25 Option "TapButton1" "0"
26 Option "TapButton2" "0"
27 Option "TapButton3" "0"
28 '';
29 pkg = pkgs.xorg.xf86inputsynaptics;
30 etcFile = "X11/xorg.conf.d/70-synaptics.conf";
31in
32{
33
34 options = {
35
36 services.xserver.synaptics = {
37
38 enable = mkOption {
39 type = types.bool;
40 default = false;
41 description = "Whether to enable touchpad support. Deprecated: Consider services.libinput.enable.";
42 };
43
44 dev = mkOption {
45 type = types.nullOr types.str;
46 default = null;
47 example = "/dev/input/event0";
48 description = ''
49 Path for touchpad device. Set to null to apply to any
50 auto-detected touchpad.
51 '';
52 };
53
54 accelFactor = mkOption {
55 type = types.nullOr types.str;
56 default = "0.001";
57 description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
58 };
59
60 minSpeed = mkOption {
61 type = types.nullOr types.str;
62 default = "0.6";
63 description = "Cursor speed factor for precision finger motion.";
64 };
65
66 maxSpeed = mkOption {
67 type = types.nullOr types.str;
68 default = "1.0";
69 description = "Cursor speed factor for highest-speed finger motion.";
70 };
71
72 scrollDelta = mkOption {
73 type = types.nullOr types.int;
74 default = null;
75 example = 75;
76 description = "Move distance of the finger for a scroll event.";
77 };
78
79 twoFingerScroll = mkOption {
80 type = types.bool;
81 default = false;
82 description = "Whether to enable two-finger drag-scrolling. Overridden by horizTwoFingerScroll and vertTwoFingerScroll.";
83 };
84
85 horizTwoFingerScroll = mkOption {
86 type = types.bool;
87 default = cfg.twoFingerScroll;
88 defaultText = literalExpression "config.${opt.twoFingerScroll}";
89 description = "Whether to enable horizontal two-finger drag-scrolling.";
90 };
91
92 vertTwoFingerScroll = mkOption {
93 type = types.bool;
94 default = cfg.twoFingerScroll;
95 defaultText = literalExpression "config.${opt.twoFingerScroll}";
96 description = "Whether to enable vertical two-finger drag-scrolling.";
97 };
98
99 horizEdgeScroll = mkOption {
100 type = types.bool;
101 default = !cfg.horizTwoFingerScroll;
102 defaultText = literalExpression "! config.${opt.horizTwoFingerScroll}";
103 description = "Whether to enable horizontal edge drag-scrolling.";
104 };
105
106 vertEdgeScroll = mkOption {
107 type = types.bool;
108 default = !cfg.vertTwoFingerScroll;
109 defaultText = literalExpression "! config.${opt.vertTwoFingerScroll}";
110 description = "Whether to enable vertical edge drag-scrolling.";
111 };
112
113 tapButtons = mkOption {
114 type = types.bool;
115 default = true;
116 description = "Whether to enable tap buttons.";
117 };
118
119 buttonsMap = mkOption {
120 type = types.listOf types.int;
121 default = [
122 1
123 2
124 3
125 ];
126 example = [
127 1
128 3
129 2
130 ];
131 description = "Remap touchpad buttons.";
132 apply = map toString;
133 };
134
135 fingersMap = mkOption {
136 type = types.listOf types.int;
137 default = [
138 1
139 2
140 3
141 ];
142 example = [
143 1
144 3
145 2
146 ];
147 description = "Remap several-fingers taps.";
148 apply = map toString;
149 };
150
151 palmDetect = mkOption {
152 type = types.bool;
153 default = false;
154 description = "Whether to enable palm detection (hardware support required)";
155 };
156
157 palmMinWidth = mkOption {
158 type = types.nullOr types.int;
159 default = null;
160 example = 5;
161 description = "Minimum finger width at which touch is considered a palm";
162 };
163
164 palmMinZ = mkOption {
165 type = types.nullOr types.int;
166 default = null;
167 example = 20;
168 description = "Minimum finger pressure at which touch is considered a palm";
169 };
170
171 horizontalScroll = mkOption {
172 type = types.bool;
173 default = true;
174 description = "Whether to enable horizontal scrolling (on touchpad)";
175 };
176
177 additionalOptions = mkOption {
178 type = types.str;
179 default = "";
180 example = ''
181 Option "RTCornerButton" "2"
182 Option "RBCornerButton" "3"
183 '';
184 description = ''
185 Additional options for synaptics touchpad driver.
186 '';
187 };
188
189 };
190
191 };
192
193 config = mkIf cfg.enable {
194
195 services.xserver.modules = [ pkg.out ];
196
197 environment.etc.${etcFile}.source = "${pkg.out}/share/X11/xorg.conf.d/70-synaptics.conf";
198
199 environment.systemPackages = [ pkg ];
200
201 services.xserver.config = ''
202 # Automatically enable the synaptics driver for all touchpads.
203 Section "InputClass"
204 Identifier "synaptics touchpad catchall"
205 MatchIsTouchpad "on"
206 ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
207 Driver "synaptics"
208 ${optionalString (cfg.minSpeed != null) ''Option "MinSpeed" "${cfg.minSpeed}"''}
209 ${optionalString (cfg.maxSpeed != null) ''Option "MaxSpeed" "${cfg.maxSpeed}"''}
210 ${optionalString (cfg.accelFactor != null) ''Option "AccelFactor" "${cfg.accelFactor}"''}
211 ${optionalString cfg.tapButtons tapConfig}
212 Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}"
213 Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}"
214 Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}"
215 Option "VertTwoFingerScroll" "${if cfg.vertTwoFingerScroll then "1" else "0"}"
216 Option "HorizTwoFingerScroll" "${if cfg.horizTwoFingerScroll then "1" else "0"}"
217 Option "VertEdgeScroll" "${if cfg.vertEdgeScroll then "1" else "0"}"
218 Option "HorizEdgeScroll" "${if cfg.horizEdgeScroll then "1" else "0"}"
219 ${optionalString cfg.palmDetect ''Option "PalmDetect" "1"''}
220 ${optionalString (
221 cfg.palmMinWidth != null
222 ) ''Option "PalmMinWidth" "${toString cfg.palmMinWidth}"''}
223 ${optionalString (cfg.palmMinZ != null) ''Option "PalmMinZ" "${toString cfg.palmMinZ}"''}
224 ${optionalString (
225 cfg.scrollDelta != null
226 ) ''Option "VertScrollDelta" "${toString cfg.scrollDelta}"''}
227 ${
228 if !cfg.horizontalScroll then
229 ''Option "HorizScrollDelta" "0"''
230 else
231 (optionalString (
232 cfg.scrollDelta != null
233 ) ''Option "HorizScrollDelta" "${toString cfg.scrollDelta}"'')
234 }
235 ${cfg.additionalOptions}
236 EndSection
237 '';
238
239 assertions = [
240 {
241 assertion = !config.services.libinput.enable;
242 message = "Synaptics and libinput are incompatible, you cannot enable both.";
243 }
244 ];
245
246 };
247
248}