Programmatically prevent Windows screensaver from starting
Asked Answered
E

14

30

Is there a recommended way to prevent the Windows screensaver from starting? The closest thing I've found is this article, but what I would really like to do is just tell Windows that the computer isn't idle rather than fooling with the currently set screensaver values.

Ellersick answered 21/1, 2009 at 1:21 Comment(2)
...do you also need to disable the system/screen from going to sleep? It's been quite a while since I actually saw a screen saver on my monitor. (Sleep seems much more likely.)Crabbing
@Eyal - hey, thanks for the idea; it never occurred to me that a delta of 0,0 might work. I've added that option as "Zen jiggle" to 1.2 (leaving the original in also, for those people who get nervous when they can't actually see it working).Kindergarten
E
14

For testing, I set the screensaver to 1 minute and required a password.

I tried capturing SC_SCREENSAVE and returning -1 in VB .Net. As commented, it works when there is no screensaver password but fails if the screensaver password is active. (I tried it in Windows XP). I also put this into a Timer's tick event, every 1000 milliseconds:

Static dir As Integer = 4
Cursor.Position = Cursor.Position + New Size(dir, dir)
dir = -dir

It doesn't work. The cursor jiggles back and forth and after 1 minute the screensaver flashes on for a short instance and then turns off. The screensaver turns on for only a moment, not long enough to require a password. But still, the flash is ugly.

Then I tried using user32.dll's SetCursorPos and GetCursorPos. You can look them up at pinvoke. Same result as above.

Then I peeked at the code of "JiggleMouse" mentioned elsewhere in this question. JiggleMouse uses SendInput. SendInput works! No flash of the screensaver. I put a call to SendInput inside of a Timer that triggers every 50 seconds (just less than the minimum screensaver timeout of 60 seconds). It's sufficient to move the mouse by a delta of 0,0, no real movement. That does work. The code to put in the Tick event:

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)))

This comes from 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
Equanimity answered 4/11, 2009 at 18:38 Comment(4)
Is this code working? I tried to convert it into C#, but I couldn't get it work (XP and Win7). I'm not sure if the problem is in my porting of code or the code doesn't work. Anybody got it in C#?Adrial
Just in case it is still relevant: Yes, it works. I ported it to Delphi and it successfully prevented the screen saver to start in Windows 8.Golgi
Ported to C# and successfully used to prevent Win 8 tablet from turning off display (running as a legacy app). ported code here: codejournal.blogspot.com/2014/01/…Evanevander
Ported to python using ctypes and was able to prevemt Windows 10 from activating screen saver.Brownout
T
9

In Windows 7+, use the Power Management API's PowerSetRequest() with PowerRequestDisplayRequired

https://msdn.microsoft.com/en-us/library/windows/desktop/dd405534(v=vs.85).aspx

In previous versions of windows, intercept the WM_SYSCOMMAND - SC_SCREENSAVE message as detailed in Eddie Parker's answer.

Tenpins answered 21/6, 2017 at 16:17 Comment(0)
F
8

Subtle. The official way to tell Windows that the system is not idle is SetThreadExecutionState. This resets the idle timer, (or turns it off, if you pass ES_CONTINUOUS ). However, even though SetThreadExecutionState resets the idle timer, it does not stop the screensaver!

Fractious answered 23/1, 2009 at 12:50 Comment(2)
Why does this answer have 6 upvotes? The answer itself states that it does not answer the question.Omaomaha
@GraemePerrow: The question is 6 years old, and back then the community did not comment as much on XY problems. Today this question might very well be closed as unclear. The body of the question specifically states "just tell Windows that the computer isn't idle", which is what this answer does.Fractious
A
7

I use Mouse Jiggler to reset the idle state. This gets around a Group Policy that tends to start my screensaver (and lock the machine) at inopportune times: when I'm reading a long document, studying a complex chunk of code, or talking/listening/not-constantly-typing during a meeting.

As it can be slightly annoying to have the mouse jump 1px diagonally every second, I intend to use AutoHotKey to write a script that does basically the same thing, but only after a configured keyboard/mouse idle timeout, and maybe use the Shift key (or Scroll Lock) instead of a mouse move.

Alwitt answered 17/9, 2009 at 16:37 Comment(3)
very nice i like this suggestionStillhunt
2 updates regarding Mouse Jiggler: The latest version supports a "Zen" mode where the mouse moves zero pixels (i.e. not at all). However, it seems that there are new Group Policy options in Windows 7 and later that somehow ignore its mouse movements.Alwitt
Look up SPI_SETBLOCKSENDINPUTRESETSPrisage
P
7

SystemParametersInfo

Specifically, the SPI_SETSCREENSAVEACTIVE parameter.

Does this not work? I was surprised that I did not see it here. Note that SetThreadExecutionState will not affect the screen saver at all, just the sleeping of the display.

Peseta answered 12/10, 2009 at 18:50 Comment(4)
Please don't go change user-global settings without explicit knowledge and consent of the user.Professed
An age-old method and the way to prevent the screensaver from running on Windows. But no one seems to remember this trick. I remembered the trick, but not the name of the function or parameter. Definitely not enough upvotes.Clintonclintonia
doesn't work without damaging the users settings. (not updaing the profile makes it 100% not work it seems)Blanchard
There is some C++ source code for this available at jacquelin.potier.free.fr/disablescreensaverMincey
P
7

From MSDN:

Windows does not start the screen saver if any of the following conditions exist:

  • The active application is not a Windows-based application.
  • A CBT window is present.
  • The active application receives the WM_SYSCOMMAND message with the wParam parameter set to the SC_SCREENSAVE value, but it does not pass the message to the DefWindowProc function.

There's a caveat though:

Windows Vista and later: If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.

That seems to apply even if you use the SetThreadExecutionState with ES_CONTINUOUS.

So, if it weren't for the caveat, your choices would be:

  1. SetThreadExecutionState with ES_CONTINUOUS (as described in other answers).
  2. Put up a computer-based training window (which requires hooks).
  3. Don't let the WM_SYSCOMMAND with SC_SCREENSAVE be passed onto DefWindowProc. (Assuming you care only when your application is the active application.)
  4. Install a dongle that simulates mouse jiggle.

The last option is nice in that it works even with the password protection policy.

Professed answered 15/8, 2011 at 17:32 Comment(0)
R
6

This blog post details what you need to do in C++.

The actual code snippet from the website:

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);

}

Rambo answered 21/1, 2009 at 1:37 Comment(3)
Note that according to MSDN, this does NOT work for Windows Vista, if a password is configured for the screensaver.Trygve
Rob, do you have a link to where it says this won't work with Vista?Ellersick
Ah, found it: "Microsoft Windows Vista and later: If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification—even if fails to pass it to DefWindowProc."Ellersick
A
5

As Adrian McCarthy mentioned from MSDN that :

If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.

So catch the event from WM_SYSCOMMAND using UINT SC_SCREENSAVE and discarded it by returning 0 or by creating a fake mouse move ("mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, 0)") will not work properly if the user enabled password-protected screen saver option.

Use SetThreadExecutionState winAPI to tell the operating system that the thread is in use, even if the user is not interacting with the computer. These will prevent to appear screen saver and stop the machine from being suspended automatically.

There are series of flags to specify a new state for the current thread:

  • ES_AWAYMODE_REQUIRED (0x00000040) : Enables away mode.
  • ES_DISPLAY_REQUIRED (0x00000002) : Forces the display to be on by resetting the display idle timer.
  • ES_SYSTEM_REQUIRED (0x00000001) : Forces the system to be in the working state by resetting the system idle timer.
  • ES_CONTINUOUS (0x80000000) : Informs the system that the state being set should remain in effect until the next call that uses ES_CONTINUOUS and one of the other state flags are cleared.

As it's a winAPI, you can call this directly in win32 or mfc application

//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);      
   }
}

If someone wants to use this in C#, must have to PInvoke this :

[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);

User-Defined Types:

[FlagsAttribute]
public enum EXECUTION_STATE :uint
{
   ES_AWAYMODE_REQUIRED = 0x00000040,
   ES_CONTINUOUS = 0x80000000,
   ES_DISPLAY_REQUIRED = 0x00000002,
   ES_SYSTEM_REQUIRED = 0x00000001
}

Here below is the calling procedure:

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);      
    }
 }

According to MSDN this API is safe also to use.

The system maintains a count of applications that have called SetThreadExecutionState. The system tracks each thread that calls SetThreadExecutionState and adjusts the counter accordingly. If this counter reaches zero and there has not been any user input, the system enters sleep.

If the Application crashed before resetting flag, the System will adjust and will reset automatically.

Albino answered 2/5, 2020 at 16:48 Comment(0)
G
4

Can't believe no one has pointed out the easy and obvious solution:

#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);
   }
}
Goltz answered 14/1, 2011 at 4:36 Comment(2)
This was suggested more than a year before you did. However, instead of actually moving the mouse cursor (like your code does), the original solution doesn't (yet still works). This answer is a poor re-implementation of an existing answer.Screwworm
Thanks @Goltz for the code. Unfortunately I'm getting the following error when compiling it. c:\C\Project>gcc test.c -o test test.c: In function 'main': test.c:6:7: error: unknown type name 'INPUT' INPUT input; ^ test.c:7:12: error: request for member 'type' in something not a structure or union input.type = INPUT_MOUSE; ^Ligation
D
2

You can use SystemParametersInfo to get the SCREENSAVETIMEOUT and then immediately set the timeout back to the same value. Do this periodically on a timer for as long as you want to prevent the screensaver from going on.

This has the effect of resetting the current countdown timer without actually changing the system setting.

You probably also want to call SetThreadExecutionState to affect the power as other answers mention.

Donavon answered 17/4, 2012 at 23:9 Comment(1)
Excellent idea, but why not use the SPI_SETSCREENSAVEACTIVE flag with the same function? It basically pretends that the screensaver is already running, preventing another one from starting. At least this used to be the method ten, twelve years back.Clintonclintonia
F
1

Just reset the timeout counter with

SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, nil, SPIF_SENDWININICHANGE);

Formless answered 12/8, 2013 at 10:19 Comment(0)
M
1

From JD Design Freeware - Flipss.exe (download 12kb) is a command line utility that will set SPI_SETSCREENSAVEACTIVE for you.

"FlipSS.exe -h" to see the current state.
"FlipSS.exe /on" to set the screensaver on.
"FlipSS.exe /off" to set the screensaver off.
Mincey answered 9/8, 2019 at 5:17 Comment(0)
P
1

I realize this is an old thread, but I'm faced with this issue for the first time (work machine is totally locked down, as far as changing super short sleep time, screensaver, etc. - I can't even change my desktop background). I've looked around at solutions, some seemingly way overcomplicated and some...not so much.

Some of my colleagues are using Caffeine. But that is surely some kind of spyware, etc., as it refuses to run if there is not an open internet connection.

So I found this (and modified it slightly), which is exactly what Caffeine does (except Caffeine does it every 59 seconds), without all the...at best, bloatware.

In PowerShell, execute the following 2 command lines:

 $WShell = New-Object -Com "Wscript.Shell"
 while(1) {$WShell.SendKeys("{F15}"); sleep 200}

Or you can make it a one-liner if you like:

while(1) {(New-Object -Com "Wscript.Shell").SendKeys("{F15}"); sleep 200}

(the latter of which seems like it would leak memory, but it does not seem to at all)

Once you run either of those, your screen will NOT lock, until you do ctrl-c, or close the Powershell window (in the latter version only, it seems, the ctrl-c may not happen until the sleep interval elapses).

Note that there is no F15 key, at least on any keyboard I've ever seen (but it's a legit windows keystroke), so there are no side effects. Now, if you your IT dept. is exceptionally paranoid, they may flag an F15 keystroke (mine is super paranoid, but they haven't noticed anything for months). If so, use something like scroll-lock instead.

Both of these 100% work on my win10 machine. Simple is good!

Pandora answered 4/11, 2021 at 19:53 Comment(3)
So I had an idea, and sure enough, this same one-liner (or two), works with "" (empty keystroke), instead of "{F15}". Doesn't get any more innocuous than that! Just don't save this as a script (so IT scans of what you have running don't see "MyCompanySux.ps1", lol). Just copy/paste it into a fresh Powershell window.Pandora
To be clear: while(1) {(New-Object -Com "Wscript.Shell").SendKeys(""); sleep 200} ...totally works, surprisinglyPandora
There are keyboards targeted at power users that go up to F15 as replacements for the nearly-useless "print screen", "scroll lock", and "pause" keys. Someone who's got one of those keyboards almost certainly has F15 bound to some action.Dumfound
M
0

AutoHotkey can set SystemParametersInfo(SPI_SETSCREENSAVEACTIVE) with a 1-liner DllCall in script to easily accomplish this with a .ahk script.

AutoHotkey code to disable Screensaver:

DllCall("SystemParametersInfo", Int, 17, Int, 0, UInt, NULL, Int, 2)

AutoHotkey code to enable screensaver:

DllCall("SystemParametersInfo", Int, 17, Int, 1, UInt, NULL, Int, 2)

Reference Forum Threads:

F13Key - Toggling Screen Saver with SystemParametersInfo
SKAN - How to Disable Screen Saver Temporarily

Mincey answered 9/8, 2019 at 5:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.