winrandr 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- winrandr-0.7.1/LICENSE +21 -0
- winrandr-0.7.1/PKG-INFO +300 -0
- winrandr-0.7.1/README.md +274 -0
- winrandr-0.7.1/pyproject.toml +79 -0
- winrandr-0.7.1/setup.cfg +4 -0
- winrandr-0.7.1/winrandr/__init__.py +65 -0
- winrandr-0.7.1/winrandr/__main__.py +5 -0
- winrandr-0.7.1/winrandr/api.py +238 -0
- winrandr-0.7.1/winrandr/cli/__init__.py +253 -0
- winrandr-0.7.1/winrandr/cli/common.py +111 -0
- winrandr-0.7.1/winrandr/cli/handlers.py +203 -0
- winrandr-0.7.1/winrandr/cli/parser.py +83 -0
- winrandr-0.7.1/winrandr/edid.py +133 -0
- winrandr-0.7.1/winrandr/features/__init__.py +1 -0
- winrandr-0.7.1/winrandr/features/gamma.py +112 -0
- winrandr-0.7.1/winrandr/features/layout.py +140 -0
- winrandr-0.7.1/winrandr/features/resolution.py +102 -0
- winrandr-0.7.1/winrandr/formatter.py +110 -0
- winrandr-0.7.1/winrandr/models.py +36 -0
- winrandr-0.7.1/winrandr/profiles.py +232 -0
- winrandr-0.7.1/winrandr/py.typed +1 -0
- winrandr-0.7.1/winrandr/win32/__init__.py +3 -0
- winrandr-0.7.1/winrandr/win32/bindings.py +100 -0
- winrandr-0.7.1/winrandr/win32/constants.py +83 -0
- winrandr-0.7.1/winrandr/win32/structures.py +175 -0
- winrandr-0.7.1/winrandr/win32/utils.py +288 -0
- winrandr-0.7.1/winrandr.egg-info/PKG-INFO +300 -0
- winrandr-0.7.1/winrandr.egg-info/SOURCES.txt +29 -0
- winrandr-0.7.1/winrandr.egg-info/dependency_links.txt +1 -0
- winrandr-0.7.1/winrandr.egg-info/entry_points.txt +2 -0
- winrandr-0.7.1/winrandr.egg-info/top_level.txt +1 -0
winrandr-0.7.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 winrandr contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
winrandr-0.7.1/PKG-INFO
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: winrandr
|
|
3
|
+
Version: 0.7.1
|
|
4
|
+
Summary: xrandr-like display configuration tool for Windows
|
|
5
|
+
Author: winrandr contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/SMWHff/winrandr
|
|
8
|
+
Project-URL: Source, https://github.com/SMWHff/winrandr
|
|
9
|
+
Project-URL: BugTracker, https://github.com/SMWHff/winrandr/issues
|
|
10
|
+
Keywords: display,xrandr,windows,monitor,multi-monitor
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Win32 (MS Windows)
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Desktop Environment
|
|
21
|
+
Classifier: Topic :: System :: Hardware
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
|
|
29
|
+
# winrandr
|
|
30
|
+
|
|
31
|
+
**Windows 上的 xrandr 替代工具**
|
|
32
|
+
|
|
33
|
+
通过 Win32 API 管理显示器布局、分辨率、刷新率、旋转、亮度、伽马校正等
|
|
34
|
+
|
|
35
|
+
[](https://github.com/SMWHff/winrandr/releases)
|
|
36
|
+
[](LICENSE)
|
|
37
|
+
[](pyproject.toml)
|
|
38
|
+
[]()
|
|
39
|
+
[](https://github.com/SMWHff/winrandr/actions/workflows/test.yml)
|
|
40
|
+
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
## 概述
|
|
44
|
+
|
|
45
|
+
`winrandr` 是 Linux `xrandr` 的 Windows 替代品,提供相同的命令行体验,用于查询和配置多显示器设置。
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 查询显示器
|
|
49
|
+
winrandr
|
|
50
|
+
|
|
51
|
+
# 设置分辨率和刷新率
|
|
52
|
+
winrandr --output DISPLAY1 --mode 1920x1080 --rate 60
|
|
53
|
+
|
|
54
|
+
# 查看所有可用分辨率
|
|
55
|
+
winrandr --listmodes
|
|
56
|
+
|
|
57
|
+
# 双屏布局
|
|
58
|
+
winrandr --output DISPLAY1 --pos 0x0 --primary
|
|
59
|
+
winrandr --output DISPLAY2 --pos 1920x0 --left-of DISPLAY1
|
|
60
|
+
|
|
61
|
+
# 图像调节
|
|
62
|
+
winrandr --output DISPLAY1 --brightness 0.8 --gamma 1.0:0.9:0.8
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 安装
|
|
66
|
+
|
|
67
|
+
### 下载 exe(推荐)
|
|
68
|
+
|
|
69
|
+
从 [Releases](https://github.com/SMWHff/winrandr/releases) 下载 `winrandr.exe`,放入 PATH 目录即可使用。
|
|
70
|
+
|
|
71
|
+
### pip 安装(暂不支持)
|
|
72
|
+
|
|
73
|
+
`winrandr` 尚未发布到 PyPI,pip 安装暂不可用。请使用 exe 或源码方式运行。
|
|
74
|
+
|
|
75
|
+
### 源码运行
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/SMWHff/winrandr.git
|
|
79
|
+
cd winrandr
|
|
80
|
+
uv run python -m winrandr --help
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 功能
|
|
84
|
+
|
|
85
|
+
### 显示器查询
|
|
86
|
+
|
|
87
|
+
| 命令 | 说明 |
|
|
88
|
+
|------|------|
|
|
89
|
+
| `winrandr` | 列出所有显示器(类 xrandr 风格) |
|
|
90
|
+
| `winrandr -q` / `--query` | 查询当前显示状态(默认行为) |
|
|
91
|
+
| `winrandr --current` | 查询当前显示状态 |
|
|
92
|
+
| `winrandr --output DISPLAY1` | 查询指定显示器 |
|
|
93
|
+
| `winrandr --listmodes` | 列出所有可用分辨率 |
|
|
94
|
+
| `winrandr --prop` | 显示显示器扩展属性(设备 ID、状态标志等) |
|
|
95
|
+
| `winrandr --json` | JSON 格式输出(脚本解析用) |
|
|
96
|
+
|
|
97
|
+
输出示例:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 32767 x 32767
|
|
101
|
+
|
|
102
|
+
DISPLAY1 connected primary 1920x1080+0+0 (normal left inverted right) 527mm x 296mm
|
|
103
|
+
1920x1080 60.00*+
|
|
104
|
+
1680x1050 60.00
|
|
105
|
+
1280x1024 60.02
|
|
106
|
+
...
|
|
107
|
+
|
|
108
|
+
DISPLAY2 disconnected
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
标记说明:`*` = 当前模式,`+` = 首选模式,旋转列表 `(normal left inverted right)` 表示所有支持方向
|
|
112
|
+
|
|
113
|
+
### 显示器配置
|
|
114
|
+
|
|
115
|
+
| 命令 | 说明 |
|
|
116
|
+
|------|------|
|
|
117
|
+
| `--output NAME` | 选择显示器 |
|
|
118
|
+
| `--mode WxH` | 设置分辨率 |
|
|
119
|
+
| `--rate Hz` | 设置刷新率 |
|
|
120
|
+
| `--preferred` | 恢复首选分辨率 |
|
|
121
|
+
| `--pos XxY` | 设置桌面位置 |
|
|
122
|
+
| `--rotate DIR` | 旋转(normal/left/right/inverted) |
|
|
123
|
+
| `--primary` | 设为主显示器 |
|
|
124
|
+
| `--off` | 关闭显示器 |
|
|
125
|
+
| `--auto` | 启用显示器并使用首选分辨率 |
|
|
126
|
+
|
|
127
|
+
### 相对定位
|
|
128
|
+
|
|
129
|
+
| 命令 | 说明 |
|
|
130
|
+
|------|------|
|
|
131
|
+
| `--left-of REF` | 放在参考显示器左侧 |
|
|
132
|
+
| `--right-of REF` | 放在参考显示器右侧 |
|
|
133
|
+
| `--above REF` | 放在参考显示器上方 |
|
|
134
|
+
| `--below REF` | 放在参考显示器下方 |
|
|
135
|
+
| `--same-as REF` | 与参考显示器同位置(镜像) |
|
|
136
|
+
|
|
137
|
+
### 图像调节
|
|
138
|
+
|
|
139
|
+
| 命令 | 说明 |
|
|
140
|
+
|------|------|
|
|
141
|
+
| `--brightness VAL` | 亮度(0.1–2.0,1.0 正常),不带 `--output` 时批量设置所有显示器 |
|
|
142
|
+
| `--gamma R:G:B` | 伽马校正(如 1.0:0.9:0.8),不带 `--output` 时批量设置所有显示器 |
|
|
143
|
+
| `--reflect xy` | 镜像翻转(等同旋转 180°) |
|
|
144
|
+
|
|
145
|
+
### 其他
|
|
146
|
+
|
|
147
|
+
| 命令 | 说明 |
|
|
148
|
+
|------|------|
|
|
149
|
+
| `--verbose` | DEBUG 级别日志 |
|
|
150
|
+
| `--version` | 显示版本号 |
|
|
151
|
+
| `--help` | 显示帮助 |
|
|
152
|
+
| `--current` | 查询当前显示状态 |
|
|
153
|
+
| `--prop` / `--properties` | 显示显示器扩展属性 |
|
|
154
|
+
| `--dry-run` / `--dryrun` | 模拟操作,不实际更改配置 |
|
|
155
|
+
| `--listproviders` | 列出 GPU 适配器 |
|
|
156
|
+
| `--listmonitors` | 带编号的显示器列表 |
|
|
157
|
+
| `--listactivemonitors` | 带编号的显示器列表(同 --listmonitors) |
|
|
158
|
+
| `--json` | JSON 格式输出(脚本解析用) |
|
|
159
|
+
| `--noprimary` | 清除所有显示器的主显示器标记 |
|
|
160
|
+
| `--identify` | 闪屏识别显示器(需配合 --output) |
|
|
161
|
+
|
|
162
|
+
### 配置存档
|
|
163
|
+
|
|
164
|
+
| 命令 | 说明 |
|
|
165
|
+
|------|------|
|
|
166
|
+
| `--save-profile NAME` | 保存当前布局为存档 |
|
|
167
|
+
| `--load-profile NAME` | 恢复存档布局 |
|
|
168
|
+
| `--load-profile NAME --dry-run` | 预览存档变更,不实际执行 |
|
|
169
|
+
| `--list-profiles` | 列出所有存档 |
|
|
170
|
+
| `--list-profiles --json` | JSON 格式输出存档列表 |
|
|
171
|
+
| `--delete-profile NAME` | 删除存档 |
|
|
172
|
+
|
|
173
|
+
## 与 xrandr 对照
|
|
174
|
+
|
|
175
|
+
| xrandr | winrandr | 状态 |
|
|
176
|
+
|--------|----------|------|
|
|
177
|
+
| `xrandr` | `winrandr` | ✅ |
|
|
178
|
+
| `-q` / `--query` | `-q` / `--query` | ✅ |
|
|
179
|
+
| `--version` / `-v` | `--version` | ✅ |
|
|
180
|
+
| `--verbose` | `--verbose` | ✅ |
|
|
181
|
+
| `--current` | `--current` | ✅ |
|
|
182
|
+
| `--dryrun` | `--dry-run, --dryrun` | ✅ |
|
|
183
|
+
| `--prop` / `--properties` | `--prop` | ✅ |
|
|
184
|
+
| `--output NAME` | `--output, -o NAME` | ✅ |
|
|
185
|
+
| `--auto` | `--auto` | ✅ |
|
|
186
|
+
| `--mode WxH` | `--mode, -m, -s WxH` | ✅ |
|
|
187
|
+
| `--preferred` | `--preferred` | ✅ |
|
|
188
|
+
| `--pos XxY` | `--pos, -p XxY` | ✅ |
|
|
189
|
+
| `--rate Hz` / `--refresh` | `--rate, -r Hz` | ✅ |
|
|
190
|
+
| `--rotate normal\|inverted\|left\|right` | `--rotate normal\|inverted\|left\|right` | ✅ |
|
|
191
|
+
| `--orientation` | `--orientation`(兼容参数) | ✅ |
|
|
192
|
+
| `-s` / `--size` | `-s` / `--size`(同 `--mode`) | ✅ |
|
|
193
|
+
| `--left-of` / `--right-of` | `--left-of` / `--right-of` | ✅ |
|
|
194
|
+
| `--above` / `--below` | `--above` / `--below` | ✅ |
|
|
195
|
+
| `--same-as` | `--same-as` | ✅ |
|
|
196
|
+
| `--primary` | `--primary` | ✅ |
|
|
197
|
+
| `--off` | `--off` | ✅ |
|
|
198
|
+
| `--brightness VAL` | `--brightness VAL` | ✅ |
|
|
199
|
+
| `--gamma r:g:b` | `--gamma R:G:B` | ✅ |
|
|
200
|
+
| `--reflect xy` | `--reflect xy` | ✅ |
|
|
201
|
+
| `--reflect normal` | `--reflect normal`(无操作) | ✅ |
|
|
202
|
+
| `-x` / `-y` | `-x` / `-y`(兼容参数) | ⚠️ 同 `--reflect x\|y`,报错提示不支持 |
|
|
203
|
+
| `--reflect x\|y` | — | ❌ 无标准 Win32 API |
|
|
204
|
+
| `--listproviders` | `--listproviders` | ✅ |
|
|
205
|
+
| `--listmonitors` | `--listmonitors` | ✅ |
|
|
206
|
+
| `--listactivemonitors` | `--listmonitors`(等效) | ⚠️ |
|
|
207
|
+
| `--noprimary` | `--noprimary` | ✅ |
|
|
208
|
+
| `--set <property> <value>` | — | ❌ 无标准 Win32 API |
|
|
209
|
+
| `--scale WxH` | — | ❌ 无标准 Win32 API |
|
|
210
|
+
| `--scale-from WxH` | — | ❌ 无标准 Win32 API |
|
|
211
|
+
| `--transform a,b,c,d,e,f,g,h,i` | — | ❌ 无标准 Win32 API |
|
|
212
|
+
| `--fb WxH` / `--fbmm WxH` | — | ❌ 无标准 Win32 API |
|
|
213
|
+
| `--panning` | — | ❌ 无标准 Win32 API |
|
|
214
|
+
| `--dpi DPI` | — | ❌ 无标准 Win32 API |
|
|
215
|
+
| `--crtc CRTC` | — | ❌ 无标准 Win32 API |
|
|
216
|
+
| `--screen SCREEN` | `--screen`(静默兼容) | ⚠️ |
|
|
217
|
+
| `--display DISPLAY` | — | ❌ 始终本地显示器 |
|
|
218
|
+
| `--nograb` | `--nograb`(静默兼容) | ⚠️ |
|
|
219
|
+
| `--newmode` / `--rmmode` | — | ❌ 无标准 Win32 API |
|
|
220
|
+
| `--addmode` / `--delmode` | — | ❌ 无标准 Win32 API |
|
|
221
|
+
| `--setmonitor` / `--delmonitor` | — | ❌ 无标准 Win32 API |
|
|
222
|
+
| `--setprovideroutputsource` | — | ❌ 无标准 Win32 API |
|
|
223
|
+
| `--setprovideroffloadsink` | — | ❌ 无标准 Win32 API |
|
|
224
|
+
|
|
225
|
+
## 自动补全
|
|
226
|
+
|
|
227
|
+
```powershell
|
|
228
|
+
# PowerShell 临时加载
|
|
229
|
+
. ./scripts/completions/completions.ps1
|
|
230
|
+
# 永久生效
|
|
231
|
+
Add-Content $PROFILE "`n. 'C:\path\to\winrandr\scripts\completions\completions.ps1'"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Bash / Zsh(WSL / Cygwin / Git Bash)
|
|
236
|
+
source scripts/completions/completions.bash
|
|
237
|
+
# 永久生效:追加到 ~/.bashrc 或 ~/.zshrc
|
|
238
|
+
echo "source '$(pwd)/scripts/completions/completions.bash'" >> ~/.bashrc
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 从源码构建
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
bash scripts/build/build.sh
|
|
245
|
+
# exe 输出到 dist/winrandr.exe
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
依赖 [uv](https://docs.astral.sh/uv/) 和 Nuitka(首次构建自动下载)。
|
|
249
|
+
|
|
250
|
+
## 测试
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
bash scripts/dev/test.sh # 集成测试(lint + pytest + 覆盖率)
|
|
254
|
+
bash scripts/dev/lint.sh # Lint 检查
|
|
255
|
+
uv run pytest tests/ -v # 单元测试(400 项,100% 覆盖率)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## 技术栈
|
|
259
|
+
|
|
260
|
+
- **语言**: Python(零外部依赖,仅标准库)
|
|
261
|
+
- **API**: Win32 `QueryDisplayConfig` / `SetDisplayConfig` / `ChangeDisplaySettingsEx` + GDI
|
|
262
|
+
- **绑定**: `ctypes` 直接调用 Win32 API
|
|
263
|
+
- **打包**: Nuitka 编译为单文件 exe
|
|
264
|
+
|
|
265
|
+
## 项目结构
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
main.py 简易入口,转发到 winrandr.cli(主要用 `python -m winrandr`)
|
|
269
|
+
winrandr/ 核心包
|
|
270
|
+
├── __init__.py 版本号 + 公开 API 重导出
|
|
271
|
+
├── __main__.py python -m winrandr 入口
|
|
272
|
+
├── cli/ CLI 子包
|
|
273
|
+
│ ├── __init__.py argparse 解析 + 主流程编排
|
|
274
|
+
│ └── handlers.py CLI 操作处理函数 + 通用工具
|
|
275
|
+
├── api.py 公开 API:list_displays / set_resolution 等
|
|
276
|
+
├── edid.py EDID 读取与解析
|
|
277
|
+
├── formatter.py xrandr 风格格式化输出
|
|
278
|
+
├── models.py 数据模型 (DisplayInfo, DisplayMode)
|
|
279
|
+
├── features/
|
|
280
|
+
│ ├── __init__.py
|
|
281
|
+
│ ├── gamma.py 伽马校正与亮度(SetDeviceGammaRamp)
|
|
282
|
+
│ ├── layout.py 位置/旋转/主屏/关闭/相对定位(SetDisplayConfig)
|
|
283
|
+
│ └── resolution.py 分辨率/刷新率枚举与设置(ChangeDisplaySettingsEx)
|
|
284
|
+
└── win32/ 底层 Win32 绑定层
|
|
285
|
+
├── __init__.py 子包统一 re-export
|
|
286
|
+
├── constants.py Win32 API 常量 + 旋转映射表
|
|
287
|
+
├── structures.py ctypes 结构体定义
|
|
288
|
+
├── bindings.py Win32 API 函数绑定 (ctypes 声明)
|
|
289
|
+
└── utils.py 内部工具函数 (查询/过滤/应用配置)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## 已知限制
|
|
293
|
+
|
|
294
|
+
- 虚拟显示器驱动(如 OrayIddDriver/向日葵)可能破坏 `SetDisplayConfig` API,导致布局相关功能不可用(分辨率调整不受影响)
|
|
295
|
+
- `--brightness` / `--gamma` 使用 `SetDeviceGammaRamp`,在某些驱动或远程桌面环境中不可用
|
|
296
|
+
- 单轴镜像翻转(`--reflect x/y`)无标准 Win32 API 支持
|
|
297
|
+
|
|
298
|
+
## 许可
|
|
299
|
+
|
|
300
|
+
[MIT](LICENSE)
|
winrandr-0.7.1/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# winrandr
|
|
4
|
+
|
|
5
|
+
**Windows 上的 xrandr 替代工具**
|
|
6
|
+
|
|
7
|
+
通过 Win32 API 管理显示器布局、分辨率、刷新率、旋转、亮度、伽马校正等
|
|
8
|
+
|
|
9
|
+
[](https://github.com/SMWHff/winrandr/releases)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](pyproject.toml)
|
|
12
|
+
[]()
|
|
13
|
+
[](https://github.com/SMWHff/winrandr/actions/workflows/test.yml)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
## 概述
|
|
18
|
+
|
|
19
|
+
`winrandr` 是 Linux `xrandr` 的 Windows 替代品,提供相同的命令行体验,用于查询和配置多显示器设置。
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# 查询显示器
|
|
23
|
+
winrandr
|
|
24
|
+
|
|
25
|
+
# 设置分辨率和刷新率
|
|
26
|
+
winrandr --output DISPLAY1 --mode 1920x1080 --rate 60
|
|
27
|
+
|
|
28
|
+
# 查看所有可用分辨率
|
|
29
|
+
winrandr --listmodes
|
|
30
|
+
|
|
31
|
+
# 双屏布局
|
|
32
|
+
winrandr --output DISPLAY1 --pos 0x0 --primary
|
|
33
|
+
winrandr --output DISPLAY2 --pos 1920x0 --left-of DISPLAY1
|
|
34
|
+
|
|
35
|
+
# 图像调节
|
|
36
|
+
winrandr --output DISPLAY1 --brightness 0.8 --gamma 1.0:0.9:0.8
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 安装
|
|
40
|
+
|
|
41
|
+
### 下载 exe(推荐)
|
|
42
|
+
|
|
43
|
+
从 [Releases](https://github.com/SMWHff/winrandr/releases) 下载 `winrandr.exe`,放入 PATH 目录即可使用。
|
|
44
|
+
|
|
45
|
+
### pip 安装(暂不支持)
|
|
46
|
+
|
|
47
|
+
`winrandr` 尚未发布到 PyPI,pip 安装暂不可用。请使用 exe 或源码方式运行。
|
|
48
|
+
|
|
49
|
+
### 源码运行
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/SMWHff/winrandr.git
|
|
53
|
+
cd winrandr
|
|
54
|
+
uv run python -m winrandr --help
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 功能
|
|
58
|
+
|
|
59
|
+
### 显示器查询
|
|
60
|
+
|
|
61
|
+
| 命令 | 说明 |
|
|
62
|
+
|------|------|
|
|
63
|
+
| `winrandr` | 列出所有显示器(类 xrandr 风格) |
|
|
64
|
+
| `winrandr -q` / `--query` | 查询当前显示状态(默认行为) |
|
|
65
|
+
| `winrandr --current` | 查询当前显示状态 |
|
|
66
|
+
| `winrandr --output DISPLAY1` | 查询指定显示器 |
|
|
67
|
+
| `winrandr --listmodes` | 列出所有可用分辨率 |
|
|
68
|
+
| `winrandr --prop` | 显示显示器扩展属性(设备 ID、状态标志等) |
|
|
69
|
+
| `winrandr --json` | JSON 格式输出(脚本解析用) |
|
|
70
|
+
|
|
71
|
+
输出示例:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 32767 x 32767
|
|
75
|
+
|
|
76
|
+
DISPLAY1 connected primary 1920x1080+0+0 (normal left inverted right) 527mm x 296mm
|
|
77
|
+
1920x1080 60.00*+
|
|
78
|
+
1680x1050 60.00
|
|
79
|
+
1280x1024 60.02
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
DISPLAY2 disconnected
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
标记说明:`*` = 当前模式,`+` = 首选模式,旋转列表 `(normal left inverted right)` 表示所有支持方向
|
|
86
|
+
|
|
87
|
+
### 显示器配置
|
|
88
|
+
|
|
89
|
+
| 命令 | 说明 |
|
|
90
|
+
|------|------|
|
|
91
|
+
| `--output NAME` | 选择显示器 |
|
|
92
|
+
| `--mode WxH` | 设置分辨率 |
|
|
93
|
+
| `--rate Hz` | 设置刷新率 |
|
|
94
|
+
| `--preferred` | 恢复首选分辨率 |
|
|
95
|
+
| `--pos XxY` | 设置桌面位置 |
|
|
96
|
+
| `--rotate DIR` | 旋转(normal/left/right/inverted) |
|
|
97
|
+
| `--primary` | 设为主显示器 |
|
|
98
|
+
| `--off` | 关闭显示器 |
|
|
99
|
+
| `--auto` | 启用显示器并使用首选分辨率 |
|
|
100
|
+
|
|
101
|
+
### 相对定位
|
|
102
|
+
|
|
103
|
+
| 命令 | 说明 |
|
|
104
|
+
|------|------|
|
|
105
|
+
| `--left-of REF` | 放在参考显示器左侧 |
|
|
106
|
+
| `--right-of REF` | 放在参考显示器右侧 |
|
|
107
|
+
| `--above REF` | 放在参考显示器上方 |
|
|
108
|
+
| `--below REF` | 放在参考显示器下方 |
|
|
109
|
+
| `--same-as REF` | 与参考显示器同位置(镜像) |
|
|
110
|
+
|
|
111
|
+
### 图像调节
|
|
112
|
+
|
|
113
|
+
| 命令 | 说明 |
|
|
114
|
+
|------|------|
|
|
115
|
+
| `--brightness VAL` | 亮度(0.1–2.0,1.0 正常),不带 `--output` 时批量设置所有显示器 |
|
|
116
|
+
| `--gamma R:G:B` | 伽马校正(如 1.0:0.9:0.8),不带 `--output` 时批量设置所有显示器 |
|
|
117
|
+
| `--reflect xy` | 镜像翻转(等同旋转 180°) |
|
|
118
|
+
|
|
119
|
+
### 其他
|
|
120
|
+
|
|
121
|
+
| 命令 | 说明 |
|
|
122
|
+
|------|------|
|
|
123
|
+
| `--verbose` | DEBUG 级别日志 |
|
|
124
|
+
| `--version` | 显示版本号 |
|
|
125
|
+
| `--help` | 显示帮助 |
|
|
126
|
+
| `--current` | 查询当前显示状态 |
|
|
127
|
+
| `--prop` / `--properties` | 显示显示器扩展属性 |
|
|
128
|
+
| `--dry-run` / `--dryrun` | 模拟操作,不实际更改配置 |
|
|
129
|
+
| `--listproviders` | 列出 GPU 适配器 |
|
|
130
|
+
| `--listmonitors` | 带编号的显示器列表 |
|
|
131
|
+
| `--listactivemonitors` | 带编号的显示器列表(同 --listmonitors) |
|
|
132
|
+
| `--json` | JSON 格式输出(脚本解析用) |
|
|
133
|
+
| `--noprimary` | 清除所有显示器的主显示器标记 |
|
|
134
|
+
| `--identify` | 闪屏识别显示器(需配合 --output) |
|
|
135
|
+
|
|
136
|
+
### 配置存档
|
|
137
|
+
|
|
138
|
+
| 命令 | 说明 |
|
|
139
|
+
|------|------|
|
|
140
|
+
| `--save-profile NAME` | 保存当前布局为存档 |
|
|
141
|
+
| `--load-profile NAME` | 恢复存档布局 |
|
|
142
|
+
| `--load-profile NAME --dry-run` | 预览存档变更,不实际执行 |
|
|
143
|
+
| `--list-profiles` | 列出所有存档 |
|
|
144
|
+
| `--list-profiles --json` | JSON 格式输出存档列表 |
|
|
145
|
+
| `--delete-profile NAME` | 删除存档 |
|
|
146
|
+
|
|
147
|
+
## 与 xrandr 对照
|
|
148
|
+
|
|
149
|
+
| xrandr | winrandr | 状态 |
|
|
150
|
+
|--------|----------|------|
|
|
151
|
+
| `xrandr` | `winrandr` | ✅ |
|
|
152
|
+
| `-q` / `--query` | `-q` / `--query` | ✅ |
|
|
153
|
+
| `--version` / `-v` | `--version` | ✅ |
|
|
154
|
+
| `--verbose` | `--verbose` | ✅ |
|
|
155
|
+
| `--current` | `--current` | ✅ |
|
|
156
|
+
| `--dryrun` | `--dry-run, --dryrun` | ✅ |
|
|
157
|
+
| `--prop` / `--properties` | `--prop` | ✅ |
|
|
158
|
+
| `--output NAME` | `--output, -o NAME` | ✅ |
|
|
159
|
+
| `--auto` | `--auto` | ✅ |
|
|
160
|
+
| `--mode WxH` | `--mode, -m, -s WxH` | ✅ |
|
|
161
|
+
| `--preferred` | `--preferred` | ✅ |
|
|
162
|
+
| `--pos XxY` | `--pos, -p XxY` | ✅ |
|
|
163
|
+
| `--rate Hz` / `--refresh` | `--rate, -r Hz` | ✅ |
|
|
164
|
+
| `--rotate normal\|inverted\|left\|right` | `--rotate normal\|inverted\|left\|right` | ✅ |
|
|
165
|
+
| `--orientation` | `--orientation`(兼容参数) | ✅ |
|
|
166
|
+
| `-s` / `--size` | `-s` / `--size`(同 `--mode`) | ✅ |
|
|
167
|
+
| `--left-of` / `--right-of` | `--left-of` / `--right-of` | ✅ |
|
|
168
|
+
| `--above` / `--below` | `--above` / `--below` | ✅ |
|
|
169
|
+
| `--same-as` | `--same-as` | ✅ |
|
|
170
|
+
| `--primary` | `--primary` | ✅ |
|
|
171
|
+
| `--off` | `--off` | ✅ |
|
|
172
|
+
| `--brightness VAL` | `--brightness VAL` | ✅ |
|
|
173
|
+
| `--gamma r:g:b` | `--gamma R:G:B` | ✅ |
|
|
174
|
+
| `--reflect xy` | `--reflect xy` | ✅ |
|
|
175
|
+
| `--reflect normal` | `--reflect normal`(无操作) | ✅ |
|
|
176
|
+
| `-x` / `-y` | `-x` / `-y`(兼容参数) | ⚠️ 同 `--reflect x\|y`,报错提示不支持 |
|
|
177
|
+
| `--reflect x\|y` | — | ❌ 无标准 Win32 API |
|
|
178
|
+
| `--listproviders` | `--listproviders` | ✅ |
|
|
179
|
+
| `--listmonitors` | `--listmonitors` | ✅ |
|
|
180
|
+
| `--listactivemonitors` | `--listmonitors`(等效) | ⚠️ |
|
|
181
|
+
| `--noprimary` | `--noprimary` | ✅ |
|
|
182
|
+
| `--set <property> <value>` | — | ❌ 无标准 Win32 API |
|
|
183
|
+
| `--scale WxH` | — | ❌ 无标准 Win32 API |
|
|
184
|
+
| `--scale-from WxH` | — | ❌ 无标准 Win32 API |
|
|
185
|
+
| `--transform a,b,c,d,e,f,g,h,i` | — | ❌ 无标准 Win32 API |
|
|
186
|
+
| `--fb WxH` / `--fbmm WxH` | — | ❌ 无标准 Win32 API |
|
|
187
|
+
| `--panning` | — | ❌ 无标准 Win32 API |
|
|
188
|
+
| `--dpi DPI` | — | ❌ 无标准 Win32 API |
|
|
189
|
+
| `--crtc CRTC` | — | ❌ 无标准 Win32 API |
|
|
190
|
+
| `--screen SCREEN` | `--screen`(静默兼容) | ⚠️ |
|
|
191
|
+
| `--display DISPLAY` | — | ❌ 始终本地显示器 |
|
|
192
|
+
| `--nograb` | `--nograb`(静默兼容) | ⚠️ |
|
|
193
|
+
| `--newmode` / `--rmmode` | — | ❌ 无标准 Win32 API |
|
|
194
|
+
| `--addmode` / `--delmode` | — | ❌ 无标准 Win32 API |
|
|
195
|
+
| `--setmonitor` / `--delmonitor` | — | ❌ 无标准 Win32 API |
|
|
196
|
+
| `--setprovideroutputsource` | — | ❌ 无标准 Win32 API |
|
|
197
|
+
| `--setprovideroffloadsink` | — | ❌ 无标准 Win32 API |
|
|
198
|
+
|
|
199
|
+
## 自动补全
|
|
200
|
+
|
|
201
|
+
```powershell
|
|
202
|
+
# PowerShell 临时加载
|
|
203
|
+
. ./scripts/completions/completions.ps1
|
|
204
|
+
# 永久生效
|
|
205
|
+
Add-Content $PROFILE "`n. 'C:\path\to\winrandr\scripts\completions\completions.ps1'"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Bash / Zsh(WSL / Cygwin / Git Bash)
|
|
210
|
+
source scripts/completions/completions.bash
|
|
211
|
+
# 永久生效:追加到 ~/.bashrc 或 ~/.zshrc
|
|
212
|
+
echo "source '$(pwd)/scripts/completions/completions.bash'" >> ~/.bashrc
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 从源码构建
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
bash scripts/build/build.sh
|
|
219
|
+
# exe 输出到 dist/winrandr.exe
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
依赖 [uv](https://docs.astral.sh/uv/) 和 Nuitka(首次构建自动下载)。
|
|
223
|
+
|
|
224
|
+
## 测试
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
bash scripts/dev/test.sh # 集成测试(lint + pytest + 覆盖率)
|
|
228
|
+
bash scripts/dev/lint.sh # Lint 检查
|
|
229
|
+
uv run pytest tests/ -v # 单元测试(400 项,100% 覆盖率)
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## 技术栈
|
|
233
|
+
|
|
234
|
+
- **语言**: Python(零外部依赖,仅标准库)
|
|
235
|
+
- **API**: Win32 `QueryDisplayConfig` / `SetDisplayConfig` / `ChangeDisplaySettingsEx` + GDI
|
|
236
|
+
- **绑定**: `ctypes` 直接调用 Win32 API
|
|
237
|
+
- **打包**: Nuitka 编译为单文件 exe
|
|
238
|
+
|
|
239
|
+
## 项目结构
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
main.py 简易入口,转发到 winrandr.cli(主要用 `python -m winrandr`)
|
|
243
|
+
winrandr/ 核心包
|
|
244
|
+
├── __init__.py 版本号 + 公开 API 重导出
|
|
245
|
+
├── __main__.py python -m winrandr 入口
|
|
246
|
+
├── cli/ CLI 子包
|
|
247
|
+
│ ├── __init__.py argparse 解析 + 主流程编排
|
|
248
|
+
│ └── handlers.py CLI 操作处理函数 + 通用工具
|
|
249
|
+
├── api.py 公开 API:list_displays / set_resolution 等
|
|
250
|
+
├── edid.py EDID 读取与解析
|
|
251
|
+
├── formatter.py xrandr 风格格式化输出
|
|
252
|
+
├── models.py 数据模型 (DisplayInfo, DisplayMode)
|
|
253
|
+
├── features/
|
|
254
|
+
│ ├── __init__.py
|
|
255
|
+
│ ├── gamma.py 伽马校正与亮度(SetDeviceGammaRamp)
|
|
256
|
+
│ ├── layout.py 位置/旋转/主屏/关闭/相对定位(SetDisplayConfig)
|
|
257
|
+
│ └── resolution.py 分辨率/刷新率枚举与设置(ChangeDisplaySettingsEx)
|
|
258
|
+
└── win32/ 底层 Win32 绑定层
|
|
259
|
+
├── __init__.py 子包统一 re-export
|
|
260
|
+
├── constants.py Win32 API 常量 + 旋转映射表
|
|
261
|
+
├── structures.py ctypes 结构体定义
|
|
262
|
+
├── bindings.py Win32 API 函数绑定 (ctypes 声明)
|
|
263
|
+
└── utils.py 内部工具函数 (查询/过滤/应用配置)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 已知限制
|
|
267
|
+
|
|
268
|
+
- 虚拟显示器驱动(如 OrayIddDriver/向日葵)可能破坏 `SetDisplayConfig` API,导致布局相关功能不可用(分辨率调整不受影响)
|
|
269
|
+
- `--brightness` / `--gamma` 使用 `SetDeviceGammaRamp`,在某些驱动或远程桌面环境中不可用
|
|
270
|
+
- 单轴镜像翻转(`--reflect x/y`)无标准 Win32 API 支持
|
|
271
|
+
|
|
272
|
+
## 许可
|
|
273
|
+
|
|
274
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=75"]
|
|
3
|
+
build-backend = "setuptools.build_meta:__legacy__"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "winrandr"
|
|
7
|
+
version = "0.7.1"
|
|
8
|
+
description = "xrandr-like display configuration tool for Windows"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "winrandr contributors"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["display", "xrandr", "windows", "monitor", "multi-monitor"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Win32 (MS Windows)",
|
|
19
|
+
"Intended Audience :: End Users/Desktop",
|
|
20
|
+
"Operating System :: Microsoft :: Windows",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Desktop Environment",
|
|
27
|
+
"Topic :: System :: Hardware",
|
|
28
|
+
]
|
|
29
|
+
dependencies = []
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/SMWHff/winrandr"
|
|
33
|
+
Source = "https://github.com/SMWHff/winrandr"
|
|
34
|
+
BugTracker = "https://github.com/SMWHff/winrandr/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
winrandr = "winrandr.cli:main"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
dev = [
|
|
41
|
+
"nuitka>=2.6",
|
|
42
|
+
"pytest>=8.0",
|
|
43
|
+
"pytest-cov>=7.1.0",
|
|
44
|
+
"ruff>=0.9",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
python_files = ["test_*.py"]
|
|
50
|
+
filterwarnings = ["ignore::DeprecationWarning"]
|
|
51
|
+
|
|
52
|
+
[tool.coverage.run]
|
|
53
|
+
source = ["winrandr"]
|
|
54
|
+
branch = true
|
|
55
|
+
|
|
56
|
+
[tool.coverage.report]
|
|
57
|
+
fail_under = 95
|
|
58
|
+
|
|
59
|
+
[tool.ruff]
|
|
60
|
+
target-version = "py310"
|
|
61
|
+
line-length = 120
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = ["E", "F", "I", "N", "W", "UP", "ANN", "BLE", "RUF", "TRY", "C90"]
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint.per-file-ignores]
|
|
67
|
+
"tests/**" = ["ANN", "RUF001", "RUF002", "RUF003"]
|
|
68
|
+
"winrandr/**" = ["RUF001", "RUF002", "RUF003"]
|
|
69
|
+
"winrandr/win32/structures.py" = ["RUF012", "N801"]
|
|
70
|
+
|
|
71
|
+
[tool.nuitka]
|
|
72
|
+
onefile = true
|
|
73
|
+
output-dir = "dist"
|
|
74
|
+
company-name = "winrandr"
|
|
75
|
+
product-name = "winrandr"
|
|
76
|
+
file-version = "0.7.1"
|
|
77
|
+
|
|
78
|
+
[tool.setuptools.packages.find]
|
|
79
|
+
include = ["winrandr*"]
|
winrandr-0.7.1/setup.cfg
ADDED