6 个版本
0.2.6 | 2024年6月9日 |
---|---|
0.2.5 | 2024年4月28日 |
0.2.4 | 2024年2月3日 |
0.2.3 | 2023年11月24日 |
0.1.1 |
|
#339 in 命令行工具
每月下载量 64
140KB
2.5K SLoC
knoll
一个用于操作 macOS 显示配置的简单命令行工具。
在为 knoll 创建软件包之前,最常见的方式可能是使用 cargo 进行安装。
Cargo
如果您已经设置了 Rust 环境,可以使用 cargo install
命令
cargo install knoll
Nix
knoll 仓库包含创建 Nix Flake 的初步尝试,但目前尚不工作。knoll 依赖于一些目前尚未打包的 macOS 框架。希望这可以在将来得到解决。
knoll 有三种主要的使用模式:管道模式、列表模式和守护进程模式。
管道模式
knoll 的默认模式支持报告和更新当前的显示配置。在最简单的情况下,您可以不带任何参数运行它
host$ knoll
[
[
{
"uuid": "b00184f4c1ee4cdf8ccfea3fca2f93b2",
"enabled": true,
"origin": [
0,
0
],
"extents": [
2560,
1440
],
"scaled": true,
"frequency": 60,
"color_depth": 8,
"rotation": 0
}
]
]
这里的输出是当前显示配置的 JSON 格式。它表示有一个位于 (0,0) 的单个启用显示,具有缩放分辨率为 2560x1440。显示未旋转,刷新频率为 60Hz,颜色深度为 8 位。
knoll 还支持 Rusty Object Notation (RON)。
host$ knoll --format=ron
[
[
(
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
enabled: true,
origin: (0, 0),
extents: (2560, 1440),
scaled: true,
frequency: 60,
color_depth: 8,
rotation: 0,
),
],
]
使用 RON 而不是 JSON 的两个主要好处是:一是它略微更紧凑;二是更重要的是,它支持注释。这样,如果您喜欢,就可以注释您的配置。JSON 被选为默认格式,因为它使 knoll 与 JSON 生态系统中的所有工具更容易接口。
您可能已经注意到显示配置嵌套了两个层级。knoll 的输出由最外层的 配置组 列表组成。每个配置组反过来又由显示配置列表组成。
默认情况下,knoll 将从标准输入读取配置组列表,并应用最具体的适用配置组。
由于 knoll 的输出是配置组,因此将 knoll 管道到自身是一个幂等操作
host$ knoll | knoll --quiet
# Should not change anything.
请注意,操作系统可能会无故障地接受某些配置更改,但为了满足某些约束而修改它们,提供knoll配置并不等同于身份。
host$ cat my_config.json | knoll > out_config.json
# my_config.json and out_config.json may differ.
这种情况最常见的是,my_config.json
省略了我们不希望调整的一些字段。另一种可能发生的情况是,如果配置组中的显示器重叠或存在间隙。我们将这些称为不稳定配置。
正如刚才提到的,显示配置可以省略您不想更改的任何字段。例如,如果您只想将显示旋转成颠倒,可以编写以下内容
host$ cat my_config.ron
[
[
(
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
rotation: 180,
),
],
]
host$ knoll --quiet --format=ron --input=my_config.ron
显示的分辨率、位置等都将保持不变。
唯一必需的字段是uuid
。如果只提供了uuid
字段,则配置实际上是无操作的。
我之前简要地提到了knoll选择“最具体”配置组的意义。有效的配置组由具有唯一UUID的一个或多个显示配置组成
[ // This is an invalid configuration group because
// there are duplicate UUIDs.
( // First configuration
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
),
( // Second configuration
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
)
]
有效的配置组列表必须仅包含不具有相同UUID集合的组。
[ // This is an invalid list of configuration groups because
// there are two groups with the same set of UUIDs.
[ // First group
(
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
),
],
[ // Second group
(
uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2",
)
],
]
鉴于这些有效性限制,当knoll运行时,将确定所有连接显示的UUID。然后,它将选择一个配置组,其中其UUID是连接显示的最大子集。这里的目的是双重的
- 将新显示器连接到计算机不会使现有配置无效。
- 可以提供包含和不包含此新显示的配置。
如果提供的配置中没有适用的显示组,knoll将退出并显示错误信息和错误代码
host$ cat bogus.ron
[
[
( // Improbable display UUID.
uuid: "11111111111111111111111111111111",
),
],
]
host$ knoll --quiet --format=ron --input=bogus.ron
No configuration group matches the currently attached displays:
37d8832a2d6602cab9f78f30a301b230, 94226c6fcef04e9b8503ffa88fedba08,
f3def94a9fbd4de79a432d9d0bc7b4ce.
host$ echo $?
1
列表模式
knoll的第二个操作模式允许检查连接显示的允许显示模式
host$ knoll list
[
{
"uuid": "37d8832a2d6602cab9f78f30a301b230",
"modes": [
{
"scaled": true,
"color_depth": 8,
"frequency": 59,
"extents": [
1280,
800
]
},
{
"scaled": true,
"color_depth": 8,
"frequency": 60,
"extents": [
1024,
768
]
}
]
}
]
这有助于确定哪些显示配置可以成功用于knoll的输入。
守护进程模式
最后,knoll还支持“守护进程”模式。
host$ knoll daemon --input=my_config.json
在此模式下,knoll将等待直到发生显示配置事件。在那个时刻,如果提供了输入文件,它将(重新)从输入参数指定的文件中加载配置。然后,如果存在适用配置组,将应用它。然而,如果没有找到适用的组,它不会以错误退出。
无论如何,knoll将继续运行并等待操作系统发出的显示重新配置事件。那时,它将等待一段时间,直到配置稳定,然后尝试找到匹配的配置并应用它。
注意,虽然knoll仍然可以接受管道配置,但由于管道的性质,它无法在重新配置事件发生时重新加载配置。
此静默期是为了避免knoll在摆弄电缆、快速打开和关闭笔记本电脑盖或显示器从休眠状态唤醒时被触发。如果默认周期对于您期望的响应速度太长,则可以配置它
host$ knoll daemon --wait=500ms --input=my_config.json
配置可以包含以下字段uuid
在JSON中:"uuid": "b00184f4c1ee4cdf8ccfea3fca2f93b2"
。在RON中:uuid: "b00184f4c1ee4cdf8ccfea3fca2f93b2"
。这用于唯一标识一个特定的显示器。这是唯一必需的字段。enabled
在 JSON 中"enabled": true
。在 RON 中enabled: true
。在 knolls 输出中,这表示是否启用了显示,在输入中则表示是否应该保持启用。由于 knoll 目前使用的 API 存在限制,禁用显示将从计算机配置中移除它。因此,一旦禁用,只能通过拔掉显示器、重启等来重新启用。origin
在 JSON 中"origin": [ 100, 100 ]
。在 RON 中origin: (100, 100)
。这指定了显示器的左上角当前或请求的位置。
显示器不能重叠,所有显示器必须接触。extents
在 JSON 中"extents": [ 2560, 1440 ]
在 RON 中extends: (2560, 1440)
。这指定了当前或请求的显示器分辨率。scaled
在 JSON 中"scaled": true
。在 RON 中scaled: true
。这指定了当前或请求的显示模式是否应该使用一对一像素或“缩放”(“Retina”)模式。frequency
在 JSON 中"frequency": 60
。在 RON 中frequency: 60
。这指定了显示器的当前或请求刷新频率,以赫兹为单位。color_depth
在 JSON 中"color_depth": 8
。在 RON 中color_depth: 8
。这指定了显示器的当前或请求的颜色深度。rotation
在 JSON 中"rotation": 90
。在 RON 中rotation: 90
。这指定了显示器的当前或请求旋转角度。目前,仅支持 0、90、180 和 270 度的旋转。
到目前为止,knoll 已经成功应用于我的特定用例。然而,仍有改进的空间。
- 修复错误。还有许多奇怪的新显示器需要探索。
- 编写更多测试。
- 支持显示镜像。我只为演示目的镜像显示器,因此我决定在第一个版本中跳过这个功能。已经有一些初始内部支持镜像的功能,但仍需要管道和测试。
- 寻找一个更好的API来启用/禁用显示器。大多数用户会期望这个功能使显示器休眠,而不是从电脑上断开。
- 检测重叠显示器或间隙的显示配置,以警告该配置不稳定。
- 支持类似于git哈希缩写的UUID缩写。
- 支持为显示器配置亮度、伽玛功能等。
- 无法轻松针对记录的输出编写测试,因为
stderrlog
目前没有提供控制输出位置的方法。 - 打包构建Nix所需的框架。
- 似乎knoll可以被扩展以支持Windows、XOrg、Wayland等。这只是一个找到适当API的问题,也许还需要对配置数据结构进行一些额外的泛化。
knoll是用Rust编写的。我尚未尝试交叉编译,但到目前为止,knoll似乎不太可能在除macOS之外的操作系统上成功编译。尽管如此,knoll实际上不依赖于任何macOS头文件等,因此应该可以在不安装XCode的情况下编译。
欢迎提交拉取请求。我仍然是一个Rust新手,因此也可能存在编写代码的更好或更符合惯用方式的途径。我已经尽力以有利于单元测试的方式编写knoll。因此,请尝试为提交的更改添加适当的测试。
knoll的名称来源于术语knolling
Kromelow会将所有移位的工具以直角排列在所有表面上,并称此为knolling,因为工具是以直角排列的 ... 结果是一个有组织的表面,使用户能够一次看到所有对象。
这似乎很合适,因为macOS目前不支持以任意角度放置显示器,而大多数用户将希望组织他们的显示器,使其清晰可见。
依赖项
~6–15MB
~215K SLoC