Programmaticamente impedisce l’avvio di screensaver di Windows

Esiste un modo consigliato per impedire l’avvio dello screensaver di Windows? La cosa più vicina che ho trovato è questo articolo , ma quello che vorrei veramente fare è dire a Windows che il computer non è inattivo piuttosto che ingannare con i valori del salvaschermo attualmente impostati.

Per il test, ho impostato lo screensaver su 1 minuto e ho richiesto una password.

Ho provato a catturare SC_SCREENSAVE e restituire -1 in VB .Net. Come commentato, funziona quando non esiste una password per lo screensaver ma fallisce se la password dello screensaver è triggers. (L’ho provato in Windows XP). Ho anche inserito questo evento in un tick tick, ogni 1000 millisecondi:

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

Non funziona. Il cursore si muove avanti e indietro e dopo 1 minuto lo screensaver lampeggia per una breve istanza e quindi si spegne. Lo screensaver si triggers solo per un momento, non abbastanza lungo da richiedere una password. Ma ancora, il flash è brutto.

Poi ho provato a utilizzare userC.dll SetCursorPos e GetCursorPos. Puoi cercarli su Pinvoke. Lo stesso risultato di sopra.

Poi ho dato un’occhiata al codice di “JiggleMouse” menzionato altrove in questa domanda. JiggleMouse utilizza SendInput. SendInput funziona! Nessun flash dello screensaver. Metto una chiamata a SendInput all’interno di un Timer che si triggers ogni 50 secondi (meno del timeout minimo di 60 secondi per lo screensaver). È sufficiente spostare il mouse di un delta di 0,0, nessun movimento reale. Questo funziona. Il codice da inserire nell’evento 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))) 

Questo proviene da 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  Public Structure MOUSEKEYBDHARDWAREINPUT  Public mi As MOUSEINPUT  Public ki As KEYBDINPUT  Public hi As HARDWAREINPUT End Structure 

SystemParametersInfo

Nello specifico, il parametro SPI_SETSCREENSAVEACTIVE .

Non funziona? Sono stato sorpreso di non averlo visto qui. Notare che SetThreadExecutionState non influirà affatto sullo screen saver, ma solo sul display.

Sottile. Il modo ufficiale per dire a Windows che il sistema non è inattivo è SetThreadExecutionState. Ciò reimposta il timer di inattività, (o lo spegne, se si passa ES_CONTINUOUS ). Tuttavia, anche se SetThreadExecutionState reimposta il timer di inattività, non interrompe lo screensaver!

Io uso Mouse Jiggler per ripristinare lo stato di inattività. Questo aggira un criterio di gruppo che tende ad avviare il mio screensaver (e bloccare la macchina) in tempi inopportuni: quando sto leggendo un lungo documento, studiando un pezzo complesso di codice, o parlando / ascoltando / non-digitando costantemente durante un incontro.

Dato che può essere leggermente fastidioso fare in modo che il mouse salti 1px in diagonale ogni secondo, ho intenzione di usare AutoHotKey per scrivere uno script che fondamentalmente fa la stessa cosa, ma solo dopo un timeout di inattività della tastiera / mouse configurato, e magari usare il tasto Shift ( o Scroll Lock) invece di una mossa del mouse.

Questo post sul blog descrive in dettaglio cosa è necessario fare in C ++.

Lo snippet di codice effettivo dal sito Web:

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

}

Non posso credere che nessuno abbia indicato la soluzione facile e ovvia:

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

Da MSDN :

Windows non avvia lo screen saver se si verifica una delle seguenti condizioni:

  • L’applicazione triggers non è un’applicazione basata su Windows.
  • Una finestra CBT è presente.
  • L’applicazione triggers riceve il messaggio WM_SYSCOMMAND con il parametro wParam impostato sul valore SC_SCREENSAVE, ma non passa il messaggio alla funzione DefWindowProc.

C’è un avvertimento però:

Windows Vista e versioni successive: se la politica di protezione della password è abilitata, lo screen saver viene avviato indipendentemente da ciò che un’applicazione fa con la notifica SC_SCREENSAVE.

Ciò sembra applicarsi anche se si utilizza SetThreadExecutionState con ES_CONTINUOUS.

Quindi, se non fosse per l’avvertimento, le tue scelte sarebbero:

  1. SetThreadExecutionState con ES_CONTINUOUS (come descritto in altre risposte).
  2. Crea una finestra di addestramento basata sul computer (che richiede ganci).
  3. Non lasciare che WM_SYSCOMMAND con SC_SCREENSAVE venga passato su DefWindowProc. (Supponendo che ti interessi solo quando la tua applicazione è l’applicazione triggers).
  4. Installa un dongle che simula il jiggle del mouse .

L’ultima opzione è buona in quanto funziona anche con la politica di protezione della password.

È ansible utilizzare SystemParametersInfo per ottenere SCREENSAVETIMEOUT e quindi impostare immediatamente il timeout sullo stesso valore. Fallo periodicamente su un timer per tutto il tempo in cui vuoi impedire lo screensaver.

Ciò ha l’effetto di reimpostare il conto alla rovescia corrente senza modificare effettivamente le impostazioni del sistema.

Probabilmente vorrai anche chiamare SetThreadExecutionState per influenzare la potenza mentre altre risposte menzionano.

In Windows 7 e versioni successive, utilizzare PowerSetRequest() dell’API di Power Management con PowerRequestDisplayRequired

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

Nelle versioni precedenti di Windows, intercettare il messaggio WM_SYSCOMMAND – SC_SCREENSAVE come descritto nella risposta di Eddie Parker.

Basta resettare il contatore del timeout con

SystemParametersInfo (SPI_SETSCREENSAVEACTIVE, 1, nil, SPIF_SENDWININICHANGE);