是否有建议的方法来阻止Windows屏幕保护程序启动?我发现最接近的是this article,但我真正想做的就是告诉Windows计算机不是空闲而不是愚弄当前设置的屏幕保护程序值。
答案 0 :(得分:10)
为了测试,我将屏幕保护程序设置为1分钟并需要密码。
我尝试捕获SC_SCREENSAVE并在VB .Net中返回-1。如评论所示,如果没有屏幕保护程序密码,则它可以正常工作;如果屏幕保护程序密码处于活动状态,则失败。 (我在Windows XP中尝试过)。我还将它放入Timer的tick事件中,每1000毫秒:
Static dir As Integer = 4
Cursor.Position = Cursor.Position + New Size(dir, dir)
dir = -dir
它不起作用。光标前后摇晃,1分钟后屏幕保护程序闪烁一小段时间,然后关闭。屏幕保护程序只开启一段时间,不够长,不需要密码。但是,闪光灯仍然是丑陋的。
然后我尝试使用user32.dll的SetCursorPos和GetCursorPos。你可以在pinvoke上查找它们。与上述结果相同。
然后我偷看了这个问题其他地方提到的“JiggleMouse”的代码。 JiggleMouse使用SendInput。 SendInput有效!屏幕保护程序没有闪烁。我在Timer中调用了SendInput,每50秒触发一次(仅比60秒的最小屏幕保护程序超时)。将鼠标移动到0,0的增量就足够了,没有真正的移动。那 工作。要放入Tick事件的代码:
Dim i(0) As INPUT
i(0).dwType = INPUT.InputType.INPUT_MOUSE
i(0).mkhi = New MOUSEKEYBDHARDWAREINPUT
i(0).mkhi.mi = New MOUSEINPUT
i(0).mkhi.mi.dx = 0
i(0).mkhi.mi.dy = 0
i(0).mkhi.mi.mouseData = 0
i(0).mkhi.mi.dwFlags = MOUSEINPUT.MouseEventFlags.MOUSEEVENTF_MOVE
i(0).mkhi.mi.time = 0
i(0).mkhi.mi.dwExtraInfo = IntPtr.Zero
SendInput(1, i(0), Marshal.SizeOf(i(0)))
这来自pinvoke.com:
Public Declare Function SendInput Lib "user32" (ByVal nInputs As Integer, ByRef pInputs As INPUT, ByVal cbSize As Integer) As Integer
Public Structure INPUT
Enum InputType As Integer
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2
End Enum
Dim dwType As InputType
Dim mkhi As MOUSEKEYBDHARDWAREINPUT
End Structure
Public Structure MOUSEINPUT
Enum MouseEventFlags As Integer
MOUSEEVENTF_MOVE = &H1
MOUSEEVENTF_LEFTDOWN = &H2
MOUSEEVENTF_LEFTUP = &H4
MOUSEEVENTF_RIGHTDOWN = &H8
MOUSEEVENTF_RIGHTUP = &H10
MOUSEEVENTF_MIDDLEDOWN = &H20
MOUSEEVENTF_MIDDLEUP = &H40
MOUSEEVENTF_XDOWN = &H80
MOUSEEVENTF_XUP = &H100
MOUSEEVENTF_WHEEL = &H800
MOUSEEVENTF_VIRTUALDESK = &H4000
MOUSEEVENTF_ABSOLUTE = &H8000
End Enum
Dim dx As Integer
Dim dy As Integer
Dim mouseData As Integer
Dim dwFlags As MouseEventFlags
Dim time As Integer
Dim dwExtraInfo As IntPtr
End Structure
Public Structure KEYBDINPUT
Public wVk As Short
Public wScan As Short
Public dwFlags As Integer
Public time As Integer
Public dwExtraInfo As IntPtr
End Structure
Public Structure HARDWAREINPUT
Public uMsg As Integer
Public wParamL As Short
Public wParamH As Short
End Structure
Const KEYEVENTF_EXTENDEDKEY As UInt32 = &H1
Const KEYEVENTF_KEYUP As UInt32 = &H2
Const KEYEVENTF_UNICODE As UInt32 = &H4
Const KEYEVENTF_SCANCODE As UInt32 = &H8
Const XBUTTON1 As UInt32 = &H1
Const XBUTTON2 As UInt32 = &H2
<StructLayout(LayoutKind.Explicit)> Public Structure MOUSEKEYBDHARDWAREINPUT
<FieldOffset(0)> Public mi As MOUSEINPUT
<FieldOffset(0)> Public ki As KEYBDINPUT
<FieldOffset(0)> Public hi As HARDWAREINPUT
End Structure
答案 1 :(得分:8)
具体来说,是SPI_SETSCREENSAVEACTIVE
参数。
这不起作用吗?我很惊讶我没有在这里看到它。请注意,SetThreadExecutionState根本不会影响屏幕保护程序,只会影响显示屏的睡眠状态。
答案 2 :(得分:7)
微妙。告诉Windows系统不空闲的官方方法是SetThreadExecutionState。这将重置空闲计时器,(如果您通过ES_CONTINUOUS
,则将其关闭)。但是,即使SetThreadExecutionState重置了空闲计时器,也不会停止屏幕保护程序!
答案 3 :(得分:6)
我使用Mouse Jiggler来重置空闲状态。这绕过了一个组策略,它倾向于在不合时宜的时间启动我的屏幕保护程序(并锁定机器):当我正在阅读一个长文档,研究一大堆代码,或者在一个时间内说话/收听/不经常打字会议。
因为让鼠标每秒对角跳1px会有点烦人,我打算用AutoHotKey编写一个基本相同的脚本,但只有在配置的键盘/鼠标空闲超时之后,并且可能使用Shift键(或Scroll Lock)而不是鼠标移动。
答案 4 :(得分:5)
无法相信没有人指出简单明了的解决方案:
#include <windows.h>
void main()
{
while(1){
INPUT input;
input.type = INPUT_MOUSE;
input.mi.dx = 1;
input.mi.dy = 1;
input.mi.mouseData = 0;
input.mi.dwFlags = MOUSEEVENTF_MOVE;
input.mi.time = 0;
input.mi.dwExtraInfo = 0;
SendInput( 1, &input, sizeof(input) );
sleep(60000);
}
}
答案 5 :(得分:5)
来自MSDN:
如果存在以下任何一种情况,Windows无法启动屏幕保护程序:
- 活动应用程序不是基于Windows的应用程序。
- 存在CBT窗口。
- 活动应用程序接收WM_SYSCOMMAND消息,并将wParam参数设置为SC_SCREENSAVE值,但它不会将消息传递给DefWindowProc函数。
但有一点需要注意:
Windows Vista及更高版本:如果策略启用了密码保护,则无论应用程序使用SC_SCREENSAVE通知执行什么操作,都会启动屏幕保护程序。
即使您将SetThreadExecutionState与ES_CONTINUOUS一起使用,这似乎也适用。
所以,如果不是警告,你的选择将是:
最后一个选项很好用,因为它甚至可以使用密码保护策略。
答案 6 :(得分:4)
This blog post详细说明了您需要在C ++中执行的操作。
网站上的实际代码段:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
return 0;
case SC_MONITORPOWER:
return 0;
}
break;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
答案 7 :(得分:3)
在Windows 7+中,使用Power Management API&{39} PowerSetRequest()
https://msdn.microsoft.com/en-us/library/windows/desktop/dd405534(v=vs.85).aspx
在以前版本的Windows中,拦截WM_SYSCOMMAND - SC_SCREENSAVE消息,详见Eddie Parker的回答。
答案 8 :(得分:2)
您可以使用SystemParametersInfo
获取SCREENSAVETIMEOUT
然后立即将超时设置回相同的值。只要您想阻止屏幕保护程序继续运行,请定期在计时器上执行此操作。
这具有重置当前倒数计时器而不实际更改系统设置的效果。
您可能还希望致电SetThreadExecutionState
以影响其他答案所提及的权力。
答案 9 :(得分:2)
Adrian McCarthy中的MSDN提到:
如果通过策略启用了密码保护,则无论应用程序如何处理SC_SCREENSAVE通知,屏幕保护程序都会启动。
因此,使用UINT SC_SCREENSAVE从WM_SYSCOMMAND捕获事件,并通过返回0或创建虚假鼠标移动(“ mouse_event(MOUSEEVENTF_MOVE,0,1,0,0)” )将其丢弃如果用户启用了受密码保护的屏幕保护程序选项,则可以正常工作。
使用SetThreadExecutionState winAPI告诉操作系统该线程正在使用中,即使用户没有与计算机进行交互。这些将防止出现屏幕保护程序并阻止计算机自动挂起。
有一系列标志可以为当前线程指定新状态:
由于它是winAPI,因此您可以在win32或mfc应用程序中直接调用
//To stop/start screen saver and monitor power off event
void SetKeepScreenOn(BOOL isKeepScreenOn)
{
if (isKeepScreenOn == TRUE)
{
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED /*| ES_AWAYMODE_REQUIRED*/);
}
else
{
SetThreadExecutionState(ES_CONTINUOUS);
}
}
如果有人想在C#中使用它,则必须PInvoke:
[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
用户定义的类型:
[FlagsAttribute]
public enum EXECUTION_STATE :uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
以下是Here的调用过程:
void SetKeepScreenOn(bool isKeepScreenOn)
{
if (isKeepScreenOn == true)
{
//You can combine several flags and specify multiple behaviors with a single call
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED /*| EXECUTION_STATE.ES_AWAYMODE_REQUIRED*/);
}
else
{
//To reset or allow those event again you have to call this API with only ES_CONTINUOUS
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
}
}
根据MSDN,此API也可以安全使用。
系统维护着称为SetThreadExecutionState的应用程序的数量。系统跟踪每个调用SetThreadExecutionState的线程,并相应地调整计数器。如果该计数器达到零,并且没有任何用户输入,则系统进入睡眠状态。
如果应用程序在重置标志前崩溃,系统将进行调整并自动重置。
答案 10 :(得分:1)
只需使用
重置超时计数器SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,1,nil,SPIF_SENDWININICHANGE);
答案 11 :(得分:1)
来自JD Design Freeware-Flipss.exe (download 12kb)的命令行实用程序将为您设置SPI_SETSCREENSAVEACTIVE。
"FlipSS.exe -h" to see the current state.
"FlipSS.exe /on" to set the screensaver on.
"FlipSS.exe /off" to set the screensaver off.
答案 12 :(得分:0)
AutoHotkey可以在脚本中使用1-liner DllCall设置SystemParametersInfo(SPI_SETSCREENSAVEACTIVE),以轻松地使用.ahk脚本来完成此操作。
禁用屏幕保护程序的AutoHotkey代码:
DllCall("SystemParametersInfo", Int, 17, Int, 0, UInt, NULL, Int, 2)
启用屏幕保护程序的AutoHotkey代码:
DllCall("SystemParametersInfo", Int, 17, Int, 1, UInt, NULL, Int, 2)
参考论坛主题:
F13Key-Toggling Screen Saver with SystemParametersInfo
SKAN-How to Disable Screen Saver Temporarily