如何在C#中立即强制将显示器切换到省电模式?

7
我有两个显示器(HP EliteDisplay E190i),都连接了两台电脑(2x VGA + DP)。这些显示器还支持DVI,所以为了不使用愚蠢的切换按钮,每当我想在两台电脑之间切换时,我都必须通过显示器菜单进行导航。我曾经有过更傻瓜的显示器,切换非常容易,但我就是无法适应整个导航过程 - 它经常让人感到困惑...
所以问题来了 - 我希望能够通过执行命令快速在两台电脑之间切换。显然,这不能直接完成(两台计算机没有任何连接),但当显示器进入省电模式(或操作系统将它们关闭)时,显示器开始扫描可用输入。这样它们就会锁定到另一台计算机上,问题解决了。
不过,话说回来,我尝试过 this solution,效果很好,但并不完美:
- 它有一个淡出动画,在显示器实际关闭前需要几秒钟的时间 - 在上述淡出动画的持续时间内,我不能触摸鼠标/键盘,否则它会被取消
我尝试在将显示器置于睡眠状态之前按照this answer的方法禁用输入,然后在5秒后重新启用它,但这也不起作用,因为:
  • 需要以管理员权限运行应用程序,否则无法阻止输入
  • 即使在以管理员权限运行时输入被阻止,我仍然可以在淡出动画期间移动鼠标或按键盘上的某些键来取消它(即使指针没有移动或键盘输入被忽略)。

以下是我的代码:

[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

[DllImport("user32.dll")]
private static extern int BlockInput(int fBlockIt);

static void Main()
{
    SendMessage(0xFFFF, 0x112, 0xF170, 2);
    try
    {
        int result = BlockInput(1);
        Console.WriteLine(result);
        Thread.Sleep(5000);
    }
    finally
    {
        BlockInput(0);
    }
}

我在两台计算机上都使用Windows 7 Enterprise x64操作系统。

有没有办法让整个程序正常工作?


那么第二种解决方案的问题是,您无法以管理员权限运行它? - Tim Freese
不,当我以管理员权限运行它时,输入被阻止了,这是预期的。然而,尽管输入被阻止,但移动鼠标或在键盘上按下一个键(物理上)会取消淡出动画 - 即使指针没有移动并且键盘输入被忽略(按下了键,但没有文本被输入到记事本中)。 - Adi Gerber
发送休眠命令之前,将输入阻止如何? - RomCoo
@RomanCoo 这个也不起作用。 - Adi Gerber
考虑过购买硬件KVM切换器吗? - NineBerry
@NineBerry 是的,但目前我的组织不允许也没有预算。 - Adi Gerber
1个回答

0

我不得不编辑我的答案,因为愚蠢的是我没有完整地阅读你的问题。

我建议创建一个应用程序,它坐落在两台计算机上,通过简单的TCP服务器/客户端套接字相互发送请求。

这将允许您例如按下PC 1上的按钮,使其进入睡眠状态并对显示器执行相同操作,并向PC 2发送消息以唤醒并窃取监视器输入。就速度而言,我想这取决于几个变量,但这可以在以后解决。

TCP客户端/服务器:

using System;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;

namespace ClientSocket_System
  {
   class tcpClientSocket
   {

    #region Global Variables

    TcpClient tcpService;
    IPEndPoint serverEndPoint;
    NetworkStream netStream;

    #endregion


    public void commToServer()
    {
        tcpService = new TcpClient();
        serverEndPoint = new IPEndPoint(IPAddress.Parse("xxx.xxx.xxx.xx"), xxxx); //Enter IP address of computer here along with a port number if needed
        try
        {
            tcpService.Connect(serverEndPoint);
            netStream = tcpService.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes("SwitchComputers");
            netStream.Write(buffer, 0, buffer.Length);
            netStream.Flush();
            tcpService.Close();
        }
        catch(Exception ex)
        {
        }
    }
   }
}

还有服务器:

using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;

namespace ClientSocket_System
{
    class tcpServerTerminal
    {



        private TcpListener tcpListener;
        private Thread listenThread;
        private TcpClient tcpService;
        string msgFromClient;



        public void ServerStart()
        {
            tcpListener = new TcpListener(IPAddress.Any, 5565);
            listenThread = new Thread(new ThreadStart(ListenForClients));
            listenThread.Start();
        }

        public void ListenForClients()
        {
            tcpListener.Start();

            while (true)
            {
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();

                //create a thread to handle communication 
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }

        public void HandleClientComm(object client)
        {
            tcpService = (TcpClient)client;

            NetworkStream netStream = tcpService.GetStream();

            byte[] message = new byte[4096];
            int bytesRead;

            while (true)
            {
                bytesRead = 0;

                try
                {
                    //blocks until a client sends a message
                    bytesRead = netStream.Read(message, 0, 4096);
                }
                catch
                {
                    //a socket error has occured
                    break;
                }

                if (bytesRead == 0)
                {
                    //the client has disconnected from the server
                    break;
                }

                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();

                msgFromClient = encoder.GetString(message, 0, bytesRead);

                if (msgFromClient == "SwitchComputers")
                {

                    //RUN CODE HERE TO ACTION PC SLEEP AND MONITOR SLEEP

                    msgFromClient = null;
                }
            }
        }

        public void SocketSend()
        {
            NetworkStream streamToClient = tcpService.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes("SwitchComputers");

            streamToClient.Write(buffer, 0, buffer.Length);
            streamToClient.Flush();
        }

    }
}

也许可以尝试这种方式,至少值得一试。虽然上述代码并不十分完善,但它可以通过您的家庭网络控制两台计算机的操作,从而实现同时执行特定命令,例如:休眠/唤醒等。

希望这能给您提供新的研究方向。

此外,我认为最佳实践是将您的输入阻止代码格式化如下:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);

这样不行。计算机之间没有任何连接(也在我的问题中提到)。此外,我主要遇到的问题是RUN CODE HERE TO ACTION PC SLEEP AND MONITOR SLEEP部分,而不是计算机之间的通信。 - Adi Gerber
抱歉,我假设它们至少都连接到房子里的路由器或调制解调器。我建议这样做的原因主要是因为当一台计算机处于睡眠状态而另一台计算机唤醒时,它会自动将数据推送到可视化引脚,这就是窃取显示器的原因,所以这将是解决您问题的有趣方法。话虽如此,当我回家后,我会提交一些代码,用于阻止我的计算机向我的监视器发送视觉信号,我们可以看看它是否比您当前的解决方案更好。 - JoeTomks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接