-1

How can I send keys to a screensaver in Windows 10. I have tried to install my own screensaver and have disabled logon screen so I only need a keypress to show my desktop. I Guess a part of the problem is use of different desktop, but even With the code shown in the link bellow I cannot figure out how to send a key Message to the screensaver. Any suggestions?

http://www.delphipraxis.net/1059352-post7.html

victor
  • 17
  • 4
  • For security reasons you won't be able to do this. Why would you need to fake input to a screensaver anyway? – David Heffernan Feb 03 '16 at 11:01
  • To disable screensaver, since the program I want to run is dependent on mouse click on the screen, and I have not figured out any other way. – victor Feb 03 '16 at 11:32
  • That makes no sense to me at all – David Heffernan Feb 03 '16 at 11:34
  • If the application wants a mouse click then the screensaver will be disabled when the mouse is moved to do that click. Or are you simulating mouse behaviour? – Blurry Sterk Feb 03 '16 at 11:50
  • Well, first a keypress or mouse click to disable screensaver, and then I can proceed With other programs and sending mouseclick to them. – victor Feb 03 '16 at 12:02
  • Have a look at SendInput along with setting SPI_SETBLOCKSENDINPUTRESETS via SystemParametersInfo. It seems from some posts that it might be an option. – Blurry Sterk Feb 04 '16 at 11:41

2 Answers2

1

This is an XY Problem. You are asking how to send keys to a screensaver to deactivate it, so it does not interfere with simulated mouse clicks you want to send to another app. That is the wrong question to ask. You should be asking how to disable the screensaver from running in the first place while your app is busy interacting with the other app.

You say you have disabled the screensaver password. In which case, you can have your app handle the WM_SYSCOMMAND message. If the message's wParam value has the SC_SCREENSAVE flag enabled, discard the message without passing it to the default message handler. Then the screensaver will not run. This only works if your app is in the foreground at the time (SC_SCREENSAVE is only sent to the foreground window), and only if the screensaver password is disabled, though:

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.

If you need to handle the message while your app is not in the foreground, you can use a global message hook via SetWindowsHookEx() to change WM_SYSCOMMAND/SC_SCREENSAVE messages into WM_NULL when being sent to any HWND in the system.

An alternative approach (only if the screensaver is not already running) is to use SystemParametersInfo() to set SPI_SETSCREENSAVEACTIVE to TRUE to make the system think that a screensaver is already running so it wont start another one (you can use SPI_GETSCREENSAVERRUNNING to check if one is running). This is an old-school way to avoid a screensaver from starting, however on Vista+ onwards with added security policies and such, this probably does not work as well as it once did.

Another alternative is to disable the screensaver in the Registry while your app is busy*. Set the HKEY_CURRENT_USER\ControlPanel\Desktop\ScreenSaveActive value to 0 (just make sure to restore it before your app exits).

*This technique is even used by Windows itself (Vista+) if the user dismisses the screensaver immediately after it starts. Windows assumes the user is annoyed with the screensaver, so the screensaver gets disabled, and is then re-enabled a few minutes later.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • About your last point; He must also take note that if his application has an abnormal termination (the app crashes or is "End tasked") then that registry setting will remain. – Blurry Sterk Feb 04 '16 at 05:38
  • Yes, and even Windows sometimes forgets to restore the setting after disabling it, thus leaving the screensaver permanently disabled. It is not a perfect system, but it is what is available. – Remy Lebeau Feb 04 '16 at 06:28
  • Don't you use SetThreadExecutionState to keep the display on? – David Heffernan Feb 04 '16 at 07:10
  • Since my program does not follow a spesific time shedule I would prefer that the screensaver is disabled when necessary. But I understand there is no simple solution. I thought it would be easy to Direct keypresses or mouse event to the screen saver desktop, but apperently it is not. – victor Feb 04 '16 at 08:28
  • @victor: the options I have presented allow you to disable the screensaver on an as-needed basis. – Remy Lebeau Feb 04 '16 at 09:06
  • 1
    @DavidHeffernan: the `SetThreadExecutionState()` documentation says: "*This function does not stop the screen saver from executing.*". – Remy Lebeau Feb 04 '16 at 09:12
  • @Remy OK, thanks. So it just keeps the screen on, even if it shows a screensaver. Seems like a weak design to me. – David Heffernan Feb 04 '16 at 09:33
  • 1
    Change of registry setting as suggested above does not disable a running screensaver on my pc. – victor Feb 04 '16 at 10:11
  • 1
    As far as I know it is not possible to automatically exit the screen saver once it is running. The only option is to prevent it from starting, and even that has become much more difficult since Windows Vista. – dummzeuch Feb 04 '16 at 15:41
  • To exit a screensaver that is already running, you can simply "jiggle" the mouse with `SendInput()`, the screensaver won't know the difference between it and the user physically moving the mouse. But, if the screensaver security policy is enabled then the user will get prompted for a password before returning control to the desktop. – Remy Lebeau Feb 04 '16 at 17:56
  • Jiggle the mouse does not work on Windows 10 on my system. – victor Feb 05 '16 at 11:42
  • @victor: I was not aware of `SPI_(GET|SET)BLOCKSENDINPUTRESETS` when I wrote that comment. From the documentation: "*a BOOL indicating whether an application can reset the screensaver's timer by calling the SendInput function to simulate keyboard or mouse input... **TRUE if the screensaver will not be deactivated by simulated input**, or FALSE if the screensaver will be deactivated by simulated input.*" So you will have to set that value to FALSE before jiggling the mouse in code. – Remy Lebeau Feb 05 '16 at 17:38
1

I had given up on this but i stumbled over the following code that Works

 function KillScreenSaverFunc(Handle: hwnd; Temp: LongInt): Boolean; stdcall;
 begin
   PostMessage(Handle, WM_CLOSE, 0, 0);
   KillScreenSaverFunc := TRUE;
 end;

procedure KillScreenSaver;
var
  myHDESK:hdesk;
begin
   myhdesk := OpenDesktop(Pchar('Screen-saver'), 0, FALSE,      
   DESKTOP_READOBJECTS or DESKTOP_WRITEOBJECTS);
   if myhdesk<>0 then begin
    EnumDesktopWindows(myhdesk, @KillScreenSaverFunc, 0);
          CloseDesktop(myhdesk);
 end;
end;
victor
  • 17
  • 4