索尼安卓电视HDMI无信号自动关机及Windows检测方案问询
问题背景
- 设备环境:索尼安卓电视通过HDMI连接Windows 10迷你PC作为显示器使用,电视本身无HDMI无信号自动关机功能,更换电视不在可选方案范围内;PC进入睡眠后电视会持续亮屏显示「无信号」提示。
- 已验证可行的控制路径:电视不支持DDC/CI控制指令,通过WiFi连接ADB执行
adb shell input keyevent KEYCODE_POWER可正常触发电视关机,手动测试验证有效。 - 核心卡点:Windows端状态检测逻辑存在缺陷,现有仅依赖
User32.dll的GetLastInputInfo()检测用户输入的方案,无法覆盖VLC、Chrome等视频播放场景——这类场景下无用户操作输入,但播放器会调用SetThreadExecutionState接口阻止系统睡眠/关闭显示器,需要准确识别系统是否被阻止进入睡眠或关闭显示器状态。 - 已排除的不可行方案:
- 检测电视硬件开关状态,不符合使用需求
- 通过
Win32_DesktopMonitor、ManagementObject读取result[n].Properties["Availability"]属性判断显示器信号输出状态,调用时直接抛出异常,无法正常获取数据 - 监听系统睡眠变更通知:系统发送「即将进入睡眠」事件后预留的程序响应时间过短,无法保证ADB完成连接、校验、发送关机指令的全流程
- 监听显示器电源变更通知:可靠性不足,仅作为备选方案
- 已尝试的其他思路:
- 查阅微软官方文档确认系统内置「关闭显示器计时器」会被
SetThreadExecutionState接口重置,但未找到C#读取该计时器状态的公开示例 - 遍历系统进程查找
SetThreadExecutionState相关调用标记,未得到有效结果 - 执行命令行
powercfg /requests可获取准确的系统睡眠阻止信息,但需要解析字符串输出,且要求程序具备管理员权限,不符合使用预期
- 查阅微软官方文档确认系统内置「关闭显示器计时器」会被
待解答问题
- 如何通过C#读取Windows「关闭显示器计时器」的状态?
- 如何在无需管理员权限的前提下,通过代码友好的方式获取与
powercfg /requests输出一致的系统睡眠阻止信息?(更新:经前期调研该需求大概率无法实现,可参考StackOverflow相关讨论结论) - 是否可直接在电视端通过安卓应用实现无信号自动关机功能?
解决方案
针对问题1:C#读取关闭显示器计时器状态
可直接调用CallNtPowerInformation Win32 API获取系统电源相关计时器状态,不需要管理员权限,核心实现逻辑如下:
- 导入
powrprof.dll中的对应API,指定查询层级为SystemPowerInformation,用结构体接收返回的系统电源状态,其中包含系统睡眠计时器剩余时间、系统空闲占比等数据。 - 核心代码示例:
using System; using System.Runtime.InteropServices; public static class PowerStatusHelper { private const int SystemPowerInformation = 12; private const uint STATUS_SUCCESS = 0; private const int SPI_GETPOWEROFFTIMEOUT = 0x0078; [StructLayout(LayoutKind.Sequential)] private struct SYSTEM_POWER_INFORMATION { public uint MaxIdlenessAllowed; public uint Idleness; public uint TimeRemaining; public byte CoolingMode; } [DllImport("powrprof.dll", SetLastError = true)] private static extern uint CallNtPowerInformation( int InformationLevel, IntPtr InputBuffer, int InputBufferLength, out SYSTEM_POWER_INFORMATION OutputBuffer, int OutputBufferLength ); [DllImport("user32.dll", SetLastError = true)] private static extern bool SystemParametersInfo(int uiAction, int uiParam, out int pvParam, int fWinIni); /// <summary> /// 获取关闭显示器计时器剩余时间,单位秒;返回uint.MaxValue代表当前有程序阻止关屏/睡眠 /// </summary> public static uint GetDisplayOffTimerRemaining() { uint ret = CallNtPowerInformation( SystemPowerInformation, IntPtr.Zero, 0, out SYSTEM_POWER_INFORMATION spi, Marshal.SizeOf(typeof(SYSTEM_POWER_INFORMATION)) ); if (ret != STATUS_SUCCESS) { throw new InvalidOperationException($"获取电源状态失败,错误码:{ret}"); } // 计时器被SetThreadExecutionState阻止时直接返回标记值 if (spi.TimeRemaining == 0xFFFFFFFF) { return uint.MaxValue; } // 读取当前电源方案配置的显示器自动关闭超时时间 SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0, out int displayTimeoutSeconds, 0); // 结合空闲占比计算剩余时间 return (uint)Math.Max(0, displayTimeoutSeconds - (displayTimeoutSeconds * spi.Idleness / 100)); } }
实际判断逻辑不需要精确到秒级:只要连续多次检测返回值为
uint.MaxValue,就代表当前有程序阻止关屏/睡眠,不需要触发关机;如果返回值持续递减到0,代表系统即将关闭显示器,此时提前触发ADB关机指令即可,不需要等待系统睡眠通知。
针对问题2:非管理员权限获取睡眠阻止信息
前期调研结论准确:powercfg /requests的数据源为内核态电源管理器,非提升权限的进程没有访问该数据的权限,不存在公开的非管理员API可以获取完整一致的结果。
可采用两种折中方案适配需求:
- 不需要精确识别阻止进程的场景下,直接使用问题1中的
CallNtPowerInformation返回值即可满足判断需求,不需要调用powercfg。 - 如果需要获取具体的阻止进程信息,可做一个轻量后台代理程序:主程序以普通权限运行,仅在需要读取阻止信息时,一次提权启动代理程序读取结果,通过命名管道回传给主程序后立刻退出代理,不需要主程序全程保持管理员权限,也不会频繁触发UAC提示。
针对问题3:电视端安卓APP实现无信号自动关机
完全可以实现,且可靠性远高于Windows端触发ADB的方案,不需要依赖PC端程序、不需要保持网络连通,实现逻辑如下:
- 安卓电视系统原生支持HDMI信号状态监听:可通过
TvInputManager获取当前活跃HDMI输入源的信号状态,部分机型可通过监听android.media.action.HDMI_AUDIO_PLUG广播补充信号丢失事件判断。 - 安卓端开发一个轻量后台服务,持续检测当前使用的HDMI端口信号状态:如果检测到无信号且持续时长超过设定阈值(比如30秒,避免信号瞬断误触发),直接调用系统电源API发送关机指令即可。
- 索尼安卓电视默认限制第三方应用关机权限,首次使用时通过ADB给APP授予
android.permission.SHUTDOWN权限,在系统设置中打开对应应用的「控制电源」开关,即可永久生效。
内容的提问来源于stack exchange,提问作者tomix89
相关产品推荐
相关产品推荐

