···24242525- [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable).
26262727+- [Buffyboard](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/tree/master/buffyboard), a framebuffer on-screen keyboard. Available as [services.buffyboard](option.html#opt-services.buffyboard).
2828+2729<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
28302931## Backward Incompatibilities {#sec-release-25.05-incompatibilities}
···11+# INTEGRATION NOTES:
22+# Buffyboard integrates as a virtual device in /dev/input
33+# which reads touch or pointer events from other input devices
44+# and generates events based on where those map to the keys it renders to the framebuffer.
55+#
66+# Buffyboard generates these events whether or not its onscreen keyboard is actually visible.
77+# Hence special care is needed if running anything which claims ownership of the display (such as a desktop environment),
88+# to avoid unwanted input events being triggered during normal desktop operation.
99+#
1010+# Desktop users are recommended to either:
1111+# 1. Stop buffyboard once your DE is started.
1212+# e.g. `services.buffyboard.unitConfig.Conflicts = [ "my-de.service" ];`
1313+# 2. Configure your DE to ignore input events from buffyboard (product-id=25209; vendor-id=26214; name=rd)
1414+# e.g. `echo 'input "26214:25209:rd" events disabled' > ~/.config/sway/config`
1515+1616+{
1717+ config,
1818+ lib,
1919+ pkgs,
2020+ utils,
2121+ ...
2222+}:
2323+let
2424+ cfg = config.services.buffyboard;
2525+ ini = pkgs.formats.ini { };
2626+in
2727+{
2828+ meta.maintainers = with lib.maintainers; [ colinsane ];
2929+3030+ options = {
3131+ services.buffyboard = with lib; {
3232+ enable = mkEnableOption "buffyboard framebuffer keyboard (on-screen keyboard)";
3333+ package = mkPackageOption pkgs "buffybox" { };
3434+3535+ extraFlags = mkOption {
3636+ type = types.listOf types.str;
3737+ default = [ ];
3838+ description = ''
3939+ Extra CLI arguments to pass to buffyboard.
4040+ '';
4141+ example = [
4242+ "--geometry=1920x1080@640,0"
4343+ "--dpi=192"
4444+ "--rotate=2"
4545+ "--verbose"
4646+ ];
4747+ };
4848+4949+ configFile = mkOption {
5050+ type = lib.types.path;
5151+ default = ini.generate "buffyboard.conf" (lib.filterAttrsRecursive (_: v: v != null) cfg.settings);
5252+ defaultText = lib.literalExpression ''ini.generate "buffyboard.conf" cfg.settings'';
5353+ description = ''
5454+ Path to an INI format configuration file to provide Buffyboard.
5555+ By default, this is generated from whatever you've set in `settings`.
5656+ If specified manually, then `settings` is ignored.
5757+5858+ For an example config file see [here](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/blob/master/buffyboard/buffyboard.conf)
5959+ '';
6060+ };
6161+6262+ settings = mkOption {
6363+ description = ''
6464+ Settings to include in /etc/buffyboard.conf.
6565+ Every option here is strictly optional:
6666+ Buffyboard will use its own baked-in defaults for those options left unset.
6767+ '';
6868+ type = types.submodule {
6969+ freeformType = ini.type;
7070+7171+ options.input.pointer = mkOption {
7272+ type = types.nullOr types.bool;
7373+ default = null;
7474+ description = ''
7575+ Enable or disable the use of a hardware mouse or other pointing device.
7676+ '';
7777+ };
7878+ options.input.touchscreen = mkOption {
7979+ type = types.nullOr types.bool;
8080+ default = null;
8181+ description = ''
8282+ Enable or disable the use of the touchscreen.
8383+ '';
8484+ };
8585+8686+ options.theme.default = mkOption {
8787+ type = types.either types.str (
8888+ types.enum [
8989+ null
9090+ "adwaita-dark"
9191+ "breezy-dark"
9292+ "breezy-light"
9393+ "nord-dark"
9494+ "nord-light"
9595+ "pmos-dark"
9696+ "pmos-light"
9797+ ]
9898+ );
9999+ default = null;
100100+ description = ''
101101+ Selects the default theme on boot. Can be changed at runtime to the alternative theme.
102102+ '';
103103+ };
104104+ options.quirks.fbdev_force_refresh = mkOption {
105105+ type = types.nullOr types.bool;
106106+ default = null;
107107+ description = ''
108108+ If true and using the framebuffer backend, this triggers a display refresh after every draw operation.
109109+ This has a negative performance impact.
110110+ '';
111111+ };
112112+ };
113113+ default = { };
114114+ };
115115+ };
116116+ };
117117+118118+ config = lib.mkIf cfg.enable {
119119+ systemd.packages = [ cfg.package ];
120120+ systemd.services.buffyboard = {
121121+ # upstream provides the service (including systemd hardening): we just configure it to start by default
122122+ # and override ExecStart so as to optionally pass extra arguments
123123+ serviceConfig.ExecStart = [
124124+ "" # clear default ExecStart
125125+ (utils.escapeSystemdExecArgs (
126126+ [
127127+ (lib.getExe' cfg.package "buffyboard")
128128+ "--config-override"
129129+ cfg.configFile
130130+ ]
131131+ ++ cfg.extraFlags
132132+ ))
133133+ ];
134134+ wantedBy = [ "getty.target" ];
135135+ before = [ "getty.target" ];
136136+ };
137137+ };
138138+}