Fedora Hyprland 外接显示器亮度路由与卡顿优化报告¶
生成时间: 2026-04-24T21:54:30+08:00
1. Problem Description¶
在 Fedora Hyprland 环境中,笔记本内置屏幕可以通过 brightnessctl 正常调节亮度,但外接显示器无法跟随同一套快捷键工作。用户希望把亮度调节统一到当前使用中的屏幕,而不是为内屏和外屏分别记忆两套快捷键;在功能打通后,又发现外接屏亮度调节明显比内屏卡顿,需要进一步定位并优化。
本次排障目标有两个:
- 让
xf86MonBrightnessDown/xf86MonBrightnessUp根据当前焦点屏幕自动路由到内屏或外屏。 - 在不改变使用方式的前提下,减少外接显示器经
ddcutil调节亮度时的等待感。
2. Environment and Scope¶
- 操作系统:Fedora
- 桌面环境:Hyprland
- 主配置目录:
/home/chesszyh/.config/hypr - 相关显示器:
- 内屏:
eDP-1 - 外屏:
HDMI-A-1,ddcutil detect --brief可识别为AOC:U27N3R - 本次涉及的关键文件:
/home/chesszyh/.config/hypr/UserConfigs/Laptops.conf/home/chesszyh/.config/hypr/UserConfigs/UserKeybinds.conf/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh- 关键工具:
hyprctlbrightnessctlddcutiljq
范围限定在 Hyprland 用户配置与显示器亮度控制链路,不涉及内核驱动、Waybar 模块或显示器 OSD 菜单重配置。
3. Symptoms and Reproduction¶
初始现象¶
- 按笔记本原有亮度键时,只能调节主屏幕亮度。
- 外接显示器亮度不会变化。
- 尝试启用备用的
Super+Alt+F11/F12外屏亮度快捷键后,仍然无效。
复现路径¶
- 保持 Hyprland 配置中
xf86MonBrightnessDown/xf86MonBrightnessUp指向Brightness.sh。 - 连接外接显示器并把焦点切到外屏。
- 按亮度键,只会调用
brightnessctl,因此只影响支持内核 backlight 的内屏。
关键证据¶
当前 Hyprland 绑定已确认改为:
1014: key: xf86MonBrightnessDown
1019: arg: /home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh --dec
1024: key: xf86MonBrightnessUp
1029: arg: /home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh --inc
当前外屏 DDC/CI 探测结果:
Display 1
I2C bus: /dev/i2c-9
DRM connector: card1-HDMI-A-1
Monitor: AOC:U27N3R:1L0R6HA002437
Invalid display
I2C bus: /dev/i2c-10
DRM connector: card1-eDP-1
Monitor: BOE::
这说明外屏支持 DDC/CI,而内屏不支持,天然需要两套不同的底层控制方式。
4. Investigation Timeline¶
- 检查现有 Hyprland 配置后,发现内屏亮度键绑定在
/home/chesszyh/.config/hypr/UserConfigs/Laptops.conf,调用的是Brightness.sh,其内部使用brightnessctl。 - 在同一配置仓库中发现已有
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh,说明外屏亮度本来就计划使用ddcutil。 - 通过
ddcutil detect和ddcutil getvcp 10 --brief验证外屏硬件链路可用,确认问题不在显示器是否支持 DDC/CI,而在配置路由与脚本实现。 - 启用备用外屏快捷键后仍无效,进一步执行
bash -n /home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh,发现脚本本身存在 Bash 语法错误,导致外屏路径根本无法执行。 - 将用户需求从“额外给外屏一套快捷键”调整为“沿用同一组亮度键,根据当前焦点屏幕自动路由”,新增
/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh作为统一入口。 - 通过
hyprctl -j activeworkspace和hyprctl -j monitors确认当前活动工作区可映射到具体显示器名称,因此可以在脚本里用焦点屏幕名决定调用Brightness.sh还是ExternalBrightness.sh。 - 完成功能后,用户反馈外屏亮度调节比内屏明显卡顿,于是对
ddcutil各子步骤分别计时,确认主要耗时集中在ddcutil detect和ddcutil getvcp。 - 继续检查
ddcutil setvcp --help,确认支持setvcp <feature-code> [+|-] <new-value>相对调节,并且可以使用--noverify关闭写后校验。 - 在
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh中加入 connector 到 display id 的缓存、短期亮度缓存,并改用--noverify setvcp 10 +/- N的相对写法,以减少重复按键时的探测与读取成本。
5. Root Cause¶
根因 1:内屏与外屏的亮度控制链路不同¶
内屏通过 brightnessctl 调用内核 backlight 接口;外屏需要通过 ddcutil 走 DDC/CI 与显示器固件通信。原始配置把 xf86MonBrightnessDown / xf86MonBrightnessUp 固定绑定到了 Brightness.sh,因此无论焦点在哪个屏幕,都会只走内屏链路。
根因 2:外屏脚本原本无法执行¶
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh 在生成通知图标路径时存在 Bash 语法错误,因此即使绑定到该脚本,外屏亮度快捷键也不会生效。
根因 3:外屏卡顿主要来自 DDC/CI 往返和重复探测¶
外屏亮度调节慢不是 Hyprland 绑定本身的问题,而是外屏控制必须经过 ddcutil 与显示器通信。原始外屏脚本在一次按键中需要做:
ddcutil detect --briefddcutil getvcp 10 --briefddcutil setvcp 10 <new>
实测单项耗时大致为:
detect 0.86
getvcp 0.33
setvcp_noverify 0.36
之前还观测到过 detect ~0.64s、getvcp ~0.58s 的情况,说明 DDC/CI 链路存在一定波动,但结论一致:重复执行 detect 与 getvcp 会显著放大卡顿感。
6. Changes Made¶
已提交变更¶
Hypr 配置仓库中已提交:
129bd3d Add focused-monitor brightness routing
该提交包含:
- 在
/home/chesszyh/.config/hypr/UserConfigs/Laptops.conf中把xf86MonBrightnessDown/xf86MonBrightnessUp改为调用BrightnessFocused.sh - 新增
/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh - 修复
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh的语法错误并支持按 connector 路由 - 启用
/home/chesszyh/.config/hypr/UserConfigs/UserKeybinds.conf中原有的外屏备用快捷键
报告生成时仍在工作区中的优化变更¶
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh 进一步加入了以下优化:
- 缓存
display_connector -> display_id - 缓存最近一次亮度值与最大亮度,默认 TTL 为 30 秒
- 调节时改用相对写法:
ddcutil --noverify setvcp 10 +/- N - 调节失败时自动清理缓存并重新探测 connector
这些优化的目标是把“每次按键都重新探测和读当前亮度”改成“只在必要时同步一次,然后在热路径上直接写”。
7. Verification¶
功能验证¶
执行过以下检查:
bash -n /home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh
bash -n /home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh
hyprctl reload
hyprctl binds | rg "xf86MonBrightness(Down|Up)|BrightnessFocused\\.sh"
ddcutil detect --brief
ddcutil --display 1 getvcp 10 --brief
关键结果:
- 两个脚本均通过 Bash 语法检查。
hyprctl reload返回ok。hyprctl binds确认亮度键已绑定到BrightnessFocused.sh。ddcutil detect --brief能识别HDMI-A-1对应的外接显示器。ddcutil --display 1 getvcp 10 --brief当前返回:
VCP 10 C 50 100
性能验证¶
热路径优化后,连续触发外屏亮度调节时,观测到的脚本耗时大致降到了:
warm inc 0.45
warm dec 0.44
而冷路径仍会包含首次同步成本,这是预期行为,因为需要重新确认当前 connector 和亮度状态。
8. Problems Encountered During Debugging¶
- 最初容易误判为“Hyprland 不支持外屏亮度键”,但实际是绑定始终指向内屏脚本。
- 启用备用快捷键后没有立刻成功,原因不是快捷键本身,而是
ExternalBrightness.sh语法错误。 hyprctl dispatch focusmonitor eDP-1的试验结果不稳定,说明把“焦点屏幕”直接建立在monitors[].focused上并不总是直观;最终优先使用activeworkspace.monitor,再回退到monitors[].focused。- 外屏性能问题如果只从用户体感出发,很容易停留在“DDC/CI 天生慢”的模糊解释。拆分成
detect、getvcp、setvcp三段分别计时后,才明确知道优化应该打在“去掉重复探测与读取”上。
9. Reuse Notes and Lessons¶
- Hyprland 多屏亮度控制不要直接假设一套脚本通吃。内屏和外屏底层能力不同,应该先判断是
brightnessctl还是ddcutil路径。 - 如果外屏完全无响应,优先做三步:
ddcutil detect --briefddcutil getvcp 10 --briefbash -n <external script>- 对于
ddcutil场景,减少调用次数通常比微调 Bash 逻辑更重要。每一次detect、getvcp、verify都是明显的用户可感知延迟来源。 - “按当前焦点屏幕自动路由”比“另外加一套外屏快捷键”更符合日常使用习惯,尤其适合笔记本接外屏场景。
- 如果以后显示器连接器名称变化,例如从
HDMI-A-1换成DP-1,优先检查缓存与 connector 解析,而不是先怀疑 Hyprland 绑定失效。
10. Appendix: Reusable Commands¶
检查当前亮度绑定¶
hyprctl binds | rg "xf86MonBrightness(Down|Up)|BrightnessFocused\\.sh"
检查当前焦点屏幕¶
hyprctl -j activeworkspace | jq -r '.monitor'
hyprctl -j monitors | jq -r '.[] | select(.focused == true) | .name'
检查外屏是否支持 DDC/CI¶
ddcutil detect --brief
ddcutil --display 1 getvcp 10 --brief
手动测试统一亮度入口¶
/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh --get
/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh --inc
/home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh --dec
直接测试外屏脚本¶
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh --connector HDMI-A-1 --get
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh --connector HDMI-A-1 --inc
/home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh --connector HDMI-A-1 --dec
语法检查与重载¶
bash -n /home/chesszyh/.config/hypr/scripts/BrightnessFocused.sh
bash -n /home/chesszyh/.config/hypr/scripts/ExternalBrightness.sh
hyprctl reload
简单计时¶
/usr/bin/time -f '%e' sh -c 'ddcutil detect --brief >/dev/null'
/usr/bin/time -f '%e' sh -c 'ddcutil --display 1 getvcp 10 --brief >/dev/null'
/usr/bin/time -f '%e' sh -c 'ddcutil --display 1 --noverify setvcp 10 + 0 >/dev/null'