How to prevent mouse from turning on monitor?

532 Views Asked by At

The following code is able to lock mouse events successfully. This was my attempt to prevent the mouse from turning on the monitor when it is off, but the monitor always turns on when executing any action with the mouse, ex: left button click.

Is there some solution to this?

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  MouseHook: HHOOK;

implementation

{$R *.dfm}

function LowLevelMouseProc(nCode: Integer; WParam: WParam; LParam: LParam): LRESULT; stdcall;
begin
  Result := 1{CallNextHookEx(MouseHook, nCode, WParam, LParam)};
  case WParam of
    WM_LBUTTONDOWN:
      Form1.Memo1.Lines.Add('Mouse Left Button Down');
    WM_LBUTTONUP:
      Form1.Memo1.Lines.Add('Mouse Left Button Up');
    WM_LBUTTONDBLCLK:
      Form1.Memo1.Lines.Add('Mouse Left Button Double Click');
    WM_RBUTTONDOWN:
      Form1.Memo1.Lines.Add('Mouse Right Button Down');
    WM_RBUTTONUP:
      Form1.Memo1.Lines.Add('Mouse Right Button Up');
    WM_RBUTTONDBLCLK:
      Form1.Memo1.Lines.Add('Mouse Right Button Double Click');
    WM_MBUTTONDOWN:
      Form1.Memo1.Lines.Add('Mouse Middle Button Down');
    WM_MBUTTONUP:
      Form1.Memo1.Lines.Add('Mouse Middle Button Up');
    WM_MBUTTONDBLCLK:
      Form1.Memo1.Lines.Add('Mouse Middle Button Double Click');
    WM_MOUSEMOVE:
      Form1.Memo1.Lines.Add('Mouse Move');
    WM_MOUSEWHEEL:
      Form1.Memo1.Lines.Add('Mouse Wheel');
  else
    Form1.Memo1.Lines.Add('Unknown Event');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
  MONITOR_ON = -1;
  MONITOR_OFF = 2;
  MONITOR_STANDBY = 1;
begin
  MouseHook := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseProc, HInstance, 0);
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);
  // SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  UnhookWindowsHookEx(MouseHook);
end;

Edit:

I need only turn off monitor without turn off system (hibernate or suspend). And prevent mouse actions revert it.

1

There are 1 best solutions below

0
FLASHCODER On BEST ANSWER

After analyze and test @AmigoJack's suggestion, seems that disable the device (like is made using Windows Device Manager) is a possible solution to me, even if some device cannot be disabled. I'm leaving the code to help future readers with this same doubt.

DeviceCtrl

unit DeviceCtrl;

interface

uses
  Classes, SysUtils, Windows;

const
  GUID_DEVCLASS_1394: TGUID = '{6BDD1FC1-810F-11D0-BEC7-08002BE2092F}';
  GUID_DEVCLASS_ADAPTER: TGUID = '{4D36E964-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_APMSUPPORT: TGUID = '{D45B1C18-C8FA-11D1-9F77-0000F805F530}';
  GUID_DEVCLASS_BATTERY: TGUID = '{72631E54-78A4-11D0-BCF7-00AA00B7B32A}';
  GUID_DEVCLASS_CDROM: TGUID = '{4D36E965-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_COMPUTER: TGUID = '{4D36E966-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_DECODER: TGUID = '{6BDD1FC2-810F-11D0-BEC7-08002BE2092F}';
  GUID_DEVCLASS_DISKDRIVE: TGUID = '{4D36E967-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_DISPLAY: TGUID = '{4D36E968-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_FDC: TGUID = '{4D36E969-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_FLOPPYDISK: TGUID = '{4D36E980-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_GPS: TGUID = '{6BDD1FC3-810F-11D0-BEC7-08002BE2092F}';
  GUID_DEVCLASS_HDC: TGUID = '{4D36E96A-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_HIDCLASS: TGUID = '{745A17A0-74D3-11D0-B6FE-00A0C90F57DA}';
  GUID_DEVCLASS_IMAGE: TGUID = '{6BDD1FC6-810F-11D0-BEC7-08002BE2092F}';
  GUID_DEVCLASS_INFRARED: TGUID = '{6BDD1FC5-810F-11D0-BEC7-08002BE2092F}';
  GUID_DEVCLASS_KEYBOARD: TGUID = '{4D36E96B-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_LEGACYDRIVER: TGUID = '{8ECC055D-047F-11D1-A537-0000F8753ED1}';
  GUID_DEVCLASS_MEDIA: TGUID = '{4D36E96C-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MEDIUM_CHANGER: TGUID = '{CE5939AE-EBDE-11D0-B181-0000F8753EC4}';
  GUID_DEVCLASS_MODEM: TGUID = '{4D36E96D-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MONITOR: TGUID = '{4D36E96E-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MOUSE: TGUID = '{4D36E96F-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MTD: TGUID = '{4D36E970-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MULTIFUNCTION: TGUID = '{4D36E971-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_MULTIPORTSERIAL: TGUID = '{50906CB8-BA12-11D1-BF5D-0000F805F530}';
  GUID_DEVCLASS_NET: TGUID = '{4D36E972-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_NETCLIENT: TGUID = '{4D36E973-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_NETSERVICE: TGUID = '{4D36E974-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_NETTRANS: TGUID = '{4D36E975-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_NODRIVER: TGUID = '{4D36E976-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_PCMCIA: TGUID = '{4D36E977-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_PORTS: TGUID = '{4D36E978-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_PRINTER: TGUID = '{4D36E979-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_PRINTERUPGRADE: TGUID = '{4D36E97A-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_SCSIADAPTER: TGUID = '{4D36E97B-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_SMARTCARDREADER: TGUID = '{50DD5230-BA8A-11D1-BF5D-0000F805F530}';
  GUID_DEVCLASS_SOUND: TGUID = '{4D36E97C-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_SYSTEM: TGUID = '{4D36E97D-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_TAPEDRIVE: TGUID = '{6D807884-7D21-11CF-801C-08002BE10318}';
  GUID_DEVCLASS_UNKNOWN: TGUID = '{4D36E97E-E325-11CE-BFC1-08002BE10318}';
  GUID_DEVCLASS_USB: TGUID = '{36FC9E60-C465-11CF-8056-444553540000}';
  GUID_DEVCLASS_VOLUME: TGUID = '{71A27CDD-812A-11D0-BEC7-08002BE2092F}';

type
  TDeviceControlResult = (DCROK, DCRErrEnumDevIceInfo, DCRErrSetClassInstallParams, DCRErrDIF_PROPERTYCHANGE);

function LoadDevices(GUID_DevClass: TGUID): TStringList;

function EnableDevice(SelectedItem: DWORD): TDeviceControlResult;

function DisableDevice(SelectedItem: DWORD): TDeviceControlResult;

implementation

const
  DIF_PROPERTYCHANGE = $00000012;
  DICS_ENABLE = $00000001;
  DICS_DISABLE = $00000002;
  DICS_FLAG_GLOBAL = $00000001;
  DIGCF_PRESENT = $00000002;
  SPDRP_DEVICEDESC = $00000000;
  SPDRP_CLASS = $00000007;
  SPDRP_CLASSGUID = $00000008;
  SPDRP_FRIENDLYNAME = $0000000C;

type
  HDEVINFO = Pointer;

  DI_FUNCTION = LongWord;

  PSPClassInstallHeader = ^TSPClassInstallHeader;

  SP_CLASSINSTALL_HEADER = packed record
    cbSize: DWORD;
    InstallFunction: DI_FUNCTION;
  end;

  TSPClassInstallHeader = SP_CLASSINSTALL_HEADER;

  PSPPropChangeParams = ^TSPPropChangeParams;

  SP_PROPCHANGE_PARAMS = packed record
    ClassInstallHeader: TSPClassInstallHeader;
    StateChange: DWORD;
    Scope: DWORD;
    HwProfile: DWORD;
  end;

  TSPPropChangeParams = SP_PROPCHANGE_PARAMS;

  PSPDevInfoData = ^TSPDevInfoData;

  SP_DEVINFO_DATA = packed record
    cbSize: DWORD;
    ClassGuid: TGUID;
    DevInst: DWORD;
    Reserved: ULONG_PTR;
  end;

  TSPDevInfoData = SP_DEVINFO_DATA;

  TSetupDiEnumDeviceInfo = function(DeviceInfoSet: HDEVINFO; MemberIndex: DWORD; var DeviceInfoData: TSPDevInfoData): LongBool; stdcall;

  TSetupDiSetClassInstallParamsA = function(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; ClassInstallParams: PSPClassInstallHeader; ClassInstallParamsSize: DWORD): LongBool; stdcall;

  TSetupDiSetClassInstallParamsW = function(DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData; ClassInstallParams: PSPClassInstallHeader; ClassInstallParamsSize: DWORD): LongBool; stdcall;

  TSetupDiSetClassInstallParams = TSetupDiSetClassInstallParamsA;

  TSetupDiCallClassInstaller = function(InstallFunction: DI_FUNCTION; DeviceInfoSet: HDEVINFO; DeviceInfoData: PSPDevInfoData): LongBool; stdcall;

  TSetupDiGetClassDevs = function(ClassGuid: PGUID; const Enumerator: PAnsiChar; hwndParent: HWND; Flags: DWORD): HDEVINFO; stdcall;

  TSetupDiGetDeviceRegistryPropertyA = function(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSIze: DWORD; var RequiredSize: DWORD): BOOL; stdcall;

  TSetupDiGetDeviceRegistryPropertyW = function(DeviceInfoSet: HDEVINFO; const DeviceInfoData: TSPDevInfoData; Property_: DWORD; var PropertyRegDataType: DWORD; PropertyBuffer: PBYTE; PropertyBufferSIze: DWORD; var RequiredSize: DWORD): BOOL; stdcall;

  TSetupDiGetDeviceRegistryProperty = TSetupDiGetDeviceRegistryPropertyA;

var
  DevInfo: hDevInfo;
  SetupDiEnumDeviceInfo: TSetupDiEnumDeviceInfo;
  SetupDiSetClassInstallParams: TSetupDiSetClassInstallParams;
  SetupDiCallClassInstaller: TSetupDiCallClassInstaller;
  SetupDiGetClassDevs: TSetupDiGetClassDevs;
  SetupDiGetDeviceRegistryProperty: TSetupDiGetDeviceRegistryProperty;

var
  SetupApiLoadCount: Integer = 0;

function LoadSetupApi: Boolean;
var
  SetupApiLib: System.THandle;
begin
  Result := True;
  Inc(SetupApiLoadCount);
  if SetupApiLoadCount > 1 then
    Exit;
  SetupApiLib := LoadLibrary('SetupApi.dll');
  Result := SetupApiLib <> 0;
  if Result then
  begin
    SetupDiEnumDeviceInfo := Windows.GetProcAddress(SetupApiLib, 'SetupDiEnumDeviceInfo');
    SetupDiSetClassInstallParams := Windows.GetProcAddress(SetupApiLib, 'SetupDiSetClassInstallParamsA');
    SetupDiCallClassInstaller := Windows.GetProcAddress(SetupApiLib, 'SetupDiCallClassInstaller');
    SetupDiGetClassDevs := Windows.GetProcAddress(SetupApiLib, 'SetupDiGetClassDevsA');
    SetupDiGetDeviceRegistryProperty := Windows.GetProcAddress(SetupApiLib, 'SetupDiGetDeviceRegistryPropertyA');
  end;
end;

function StateChange(NewState, SelectedItem: DWORD; hDevInfo: hDevInfo): TDeviceControlResult;
var
  PropChangeParams: TSPPropChangeParams;
  DeviceInfoData: TSPDevInfoData;
begin
  PropChangeParams.ClassInstallHeader.cbSize := SizeOf(TSPClassInstallHeader);
  DeviceInfoData.cbSize := SizeOf(TSPDevInfoData);

  if (not SetupDiEnumDeviceInfo(hDevInfo, SelectedItem, DeviceInfoData)) then
  begin
    Result := DCRErrEnumDevIceInfo;
    Exit;
  end;

  PropChangeParams.ClassInstallHeader.InstallFunction := DIF_PROPERTYCHANGE;
  PropChangeParams.Scope := DICS_FLAG_GLOBAL;
  PropChangeParams.StateChange := NewState;
  if (not SetupDiSetClassInstallParams(hDevInfo, @DeviceInfoData, PSPClassInstallHeader(@PropChangeParams), SizeOf(PropChangeParams))) then
  begin
    Result := DCRErrSetClassInstallParams;
    Exit;
  end;

  if (not SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, @DeviceInfoData)) then
  begin
    Result := DCRErrDIF_PROPERTYCHANGE;
    Exit;
  end;
  Result := DCROK;
end;

function GetRegistryProperty(PnPHandle: hDevInfo; DevData: TSPDevInfoData; Prop: DWORD; Buffer: PChar; dwLength: DWORD): Boolean;
var
  aBuffer: array[0..256] of Char;
begin
  dwLength := 0;
  aBuffer[0] := #0;
  SetupDiGetDeviceRegistryProperty(PnPHandle, DevData, Prop, Prop, PBYTE(@aBuffer[0]), SizeOf(aBuffer), dwLength);
  StrCopy(Buffer, aBuffer);
  Result := Buffer^ <> #0;
end;

function ConstructDeviceName(DeviceInfoSet: hDevInfo; DeviceInfoData: TSPDevInfoData; Buffer: PChar; dwLength: DWORD): Boolean;
const
  UnknownDevice = '<Unknown DevIce>';
begin
  if (not GetRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME, Buffer, dwLength)) then
  begin
    if (not GetRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_DEVICEDESC, Buffer, dwLength)) then
    begin
      if (not GetRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_CLASS, Buffer, dwLength)) then
      begin
        if (not GetRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_CLASSGUID, Buffer, dwLength)) then
        begin
          dwLength := DWORD(SizeOf(UnknownDevice));
          Buffer := Pointer(LocalAlloc(LPTR, Cardinal(dwLength)));
          StrCopy(Buffer, UnknownDevice);
        end;
      end;
    end;
  end;
  Result := True;
end;

function LoadDevices(GUID_DevClass: TGUID): TStringList;
var
  DeviceInfoData: TSPDevInfoData;
  I: DWORD;
  pszText: PChar;
begin
  if (not LoadSetupApi) then
  begin
    Result := nil;
    Exit;
  end;
  DevInfo := nil;

  DevInfo := SetupDiGetClassDevs(@GUID_DevClass, nil, 0, DIGCF_PRESENT);
  if (DevInfo = Pointer(INVALID_HANDLE_VALUE)) then
  begin
    Result := nil;
    Exit;
  end;
  Result := TStringList.Create;
  DeviceInfoData.cbSize := SizeOf(TSPDevInfoData);
  I := 0;

  while SetupDiEnumDeviceInfo(DevInfo, I, DeviceInfoData) do
  begin
    GetMem(pszText, 256);
    try
      ConstructDeviceName(DevInfo, DeviceInfoData, pszText, DWORD(nil));
      Result.AddObject(string(PAnsiChar(pszText)), Tobject(I));
    finally
      FreeMem(pszText);
    end;
    Inc(I);
  end;
end;

function EnableDevice(SelectedItem: DWORD): TDeviceControlResult;
begin
  Result := StateChange(DICS_ENABLE, SelectedItem, DevInfo);
end;

function DisableDevice(SelectedItem: DWORD): TDeviceControlResult;
begin
  Result := StateChange(DICS_DISABLE, SelectedItem, DevInfo);
end;

end.

DeviceTest

program DeviceTest;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Classes,
  DeviceCtrl;

var
  sl: TStringList;
  I: Integer;

begin
  sl := LoadDevices(GUID_DEVCLASS_MOUSE);
  try
    for I := 0 to sl.count - 1 do
    begin
      Writeln(I, ' : ', sl[I]);
      if DisableDevice(I) = DCROK then
        Writeln(sl[I], ' disabled');
      if EnableDevice(I) = DCROK then
        Writeln(sl[I], ' enabled');
    end;
  finally
    sl.Free;
  end;
  Readln;
end.