¿Nunca se os ha ocurrido apagarle a alguien el monitor por código de forma que no pueda encenderlo?, a mi sí y no voy a decir porqué
Apagar el monitor es fácil con SC_MONITORPOWER pero en cuanto se toca el teclado o el ratón, se enciende. Para darle consistencia al apagado he escrito un thread que repite el apagado cada 100 ms y listo. Pero al hacer eso el usuario cambiaría cosas inconscientemente en las aplicaciones en primer plano al tratar de activar el monitor aporreando el teclado o interactuando desesperadamente con el ratón. Para solucionar este inconveniente bloqueo el teclado y el ratón.
¡Ni monitor, ni teclado ni ratón! Que no cunda el pánico, que las combinaciones de teclas en un hook al teclado nos abren la puerta:
ALT - F10: Cierra el programa devolviéndonos el control.
ALT - F11: Nos devuelve el control sin cerrar el programa.
ALT - F12: Apaga el monitor y bloquea el teclado + ratón.
La aplicación no tiene interface gráfico y queda como sigue:
program MonitorPower; uses Windows, Messages; var idThTurnOffMonitor: DWORD = 0; WHookKeyboard: HHOOK = 0; WHookMouse: HHOOK = 0; function ThTurnOffMonitor(): DWORD; stdcall var msg: TMsg; i: DWORD; begin // Monitor off repeat PeekMessage(msg,0,0,0, PM_REMOVE); Sleep(100); SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, 2); DispatchMessage(msg); until (msg.Message = WM_QUIT); // Monitor on SendNotifyMessage(GetForegroundWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, -1); for i:= 0 to 4 do begin mouse_event(MOUSEEVENTF_MOVE, 0, 10, 0, 0); Sleep(40); mouse_event(MOUSEEVENTF_MOVE, 0, DWORD(-10), 0, 0); end; Result:= 0; end; procedure CmdEnableMonitor(Enable: BOOL); begin if not Enable and (idThTurnOffMonitor = 0) then // Turn off monitor CloseHandle(CreateThread(nil, 0, @ThTurnOffMonitor, nil, 0, idThTurnOffMonitor)); if Enable then begin // Turn on monitor PostThreadMessage(idThTurnOffMonitor, WM_QUIT, 0, 0); idThTurnOffMonitor:= 0; end; end; function KeyboardHook(Code, wParam, lParam: Integer): Integer; stdcall; begin if (Code = HC_ACTION) and LongBool(PDWORD(lParam + 8)^ and $20{LLKHF_ALTDOWN}) then begin if PDWORD(lParam)^ = VK_F11 then // ALT + F11: Monitor Off CmdEnableMonitor(true); if PDWORD(lParam)^ = VK_F12 then // ALT + F12: Monitor On CmdEnableMonitor(false); if PDWORD(lParam)^ = VK_F10 then // ALT + F10: Quit PostThreadMessage(GetCurrentThreadId, WM_QUIT, 0, 0); end; Result:= -1; if idThTurnOffMonitor = 0 then Result:= CallNextHookEx(WHookKeyboard, Code, wParam, lParam); end; function MouseHook(Code, wParam, lParam: Integer): Integer; stdcall; begin Result:= -1; if (Code <> HC_ACTION) or (idThTurnOffMonitor = 0) then Result:= CallNextHookEx(WHookMouse, Code, wParam, lParam); end; var msg: TMsg; begin idThTurnOffMonitor:= 0; WHookKeyboard:= SetWindowsHookEx(13{WH_KEYBOARD_LL}, @KeyboardHook, HInstance, 0); WHookMouse:= SetWindowsHookEx(14{WH_MOUSE_LL}, @KeyboardHook, HInstance, 0); // Bucle de mensajes: repeat GetMessage(msg, 0, 0, 0); DispatchMessage(msg); until (msg.Message = WM_QUIT); CmdEnableMonitor(true); UnhookWindowsHookEx(WHookKeyboard); UnhookWindowsHookEx(WHookMouse); end.
El código puede tener su utilidad como botón del pánico, una broma no demasiado pesada o... la imaginación es libre.
Saludos.