You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForms托盘程序:鼠标点击可休眠显示器,快捷键触发后立即唤醒

修复快捷键触发显示器休眠后立即唤醒的问题

我开发了一个C# WinForms系统托盘应用,目标是通过点击托盘图标或Ctrl + Alt + S快捷键让所有显示器休眠。点击托盘图标时功能正常,但使用快捷键触发时,显示器会进入休眠状态后立即唤醒,即便没有触碰键盘或鼠标。

现有代码展示

显示器休眠核心实现

private int SC_MONITORPOWER = 0xF170;
private uint WM_SYSCOMMAND = 0x0112;

[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

private void SchnozOff()
{
    SendMessage(this.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
}

托盘图标点击事件(工作正常)

private void sysTrayIcon_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        SchnozOff();
    }
    else if (e.Button == MouseButtons.Middle)
    {
        Application.Exit();
    }
}

快捷键相关代码(存在问题)

[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

private const int MYACTION_HOTKEY_ID = 1;
private void RegisterHotkeys()
{
    int Ctrl = 1;
    int Alt = 2;
    RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, Ctrl + Alt, (int)Keys.S);
}

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
    {
        SchnozOff();
    }
    base.WndProc(ref m);
}

问题原因及修复方案

核心原因

快捷键触发后,系统会保留按键的按下状态,这些未处理的按键消息会在显示器休眠后被系统识别为输入操作,从而立即唤醒显示器。另外,原代码中修饰符常量的定义存在逻辑混淆(把Ctrl设为1、Alt设为2,虽然组合值正确,但不符合系统定义的常量规范)。

修复步骤及代码

  1. 修正修饰符常量定义
    使用系统标准的修饰符常量,避免逻辑混淆:
private const int MOD_ALT = 0x0001;
private const int MOD_CONTROL = 0x0002;

private void RegisterHotkeys()
{
    RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, MOD_ALT | MOD_CONTROL, (int)Keys.S);
}
  1. 拦截并终止快捷键消息传递
    在WndProc中处理完快捷键后,直接返回不调用基类方法,避免系统继续处理该按键消息:
protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
    {
        SchnozOff();
        // 终止消息传递,避免后续处理触发唤醒
        return;
    }
    base.WndProc(ref m);
}
  1. 优化休眠指令发送逻辑
    将休眠消息发送到所有顶级窗口(用IntPtr.Zero作为窗口句柄),确保所有显示器都能接收到休眠指令,同时增加短暂延迟让系统完成休眠操作:
private void SchnozOff()
{
    // 发送消息到所有顶级窗口,覆盖所有显示器
    SendMessage(IntPtr.Zero, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
    // 短暂延迟确保系统完成休眠
    System.Threading.Thread.Sleep(100);
}

通过以上修改,快捷键触发显示器休眠后就不会再出现立即唤醒的问题了。

内容的提问来源于stack exchange,提问作者Alex Dobson-Pleming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 18:37:52