WM_INPUTを最前面にいなくても受け取るには?

解決


QUEBits  2005-11-27 01:26:14  No: 18907

WindowsXP (SP1以降)でMCE対応リモコンを使う
http://homepage1.nifty.com/ht_deko/tech003.html
を参考にして、
procedure WmInput(var Mess: TMessage); message WM_INPUT;
で、WM_INPUT メッセージを受け取るようにして、
WM_INPUT が含んでいるデバイスのハンドルを使って、
GetRawInput 関係のAPI(XP以降対応)を使うことができたのですが、
ウィンドウが最前面、アクティブになっているときにしかメッセージを受け取れません。

そこで、グローバルフックを使ってメッセージを受け取ればいいと考えたのですが、
WH_MOUSE_LL は、
WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE、WM_MOUSEWHEEL、WM_RBUTTONDOWN、WM_RBUTTONUP
WH_KEYBOARD_LLは、
WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP
にしか対応していなく、WM_INPUTをフックできません。

プログラムが最前面になくても(タスクトレイに入っていても)、
WM_INPUT を受け取って処理するにはどうすればいいのでしょうか?


QUEBits  2005-11-27 06:18:21  No: 18908

RAWINPUTDEVICE 構造体の
dwFlags に RIDEV_INPUTSINK
hwndTarget 自分のハンドル
を指定することで、フックを使わずに
WM_INPUT メッセージを受け取れました。

参考:
RegisterRawInputDevices
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/rawinput/rawinputreference/rawinputfunctions/registerrawinputdevices.asp
>Remarks
>To receive WM_INPUT messages, an application must first register the raw input devices using RegisterRawInputDevices. By default, an application does not receive raw input.

RAWINPUTDEVICE structure 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/rawinput/rawinputreference/rawinputstructures/rawinputdevice.asp
>hwndTarget
>    Handle to the target device. If NULL, it follows the keyboard focus.
    (Handle to the "Window" の間違い?)

Using Alternate Input Devices in Your Smart Client Applications
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwinforms/html/altinputdevices.asp


QUEBits  2005-11-27 06:23:34  No: 18909

{
一応、誰かの役に立つかもしれないので、ソースも書いときます。
XP以降対応
}

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

////////////////////////////////////////////////////////////////////////////////

type
  USHORT = Word;

////////////////////////////////////////////////////////////////////////////////

const
  RI_NUM_DEVICE = 2;

const
  WM_INPUT  = $00FF;

const
  RIDEV_REMOVE                = $00000001;
  RIDEV_EXCLUDE               = $00000010;
  RIDEV_PAGEONLY              = $00000020;
  RIDEV_NOLEGACY              = $00000030;
  RIDEV_INPUTSINK             = $00000100;
  RIDEV_CAPTUREMOUSE          = $00000200;
  RIDEV_NOHOTKEYS             = $00000200;
  RIDEV_APPKEYS               = $00000400;

  RIM_TYPEMOUSE               = $00000000;
  RIM_TYPEKEYBOARD            = $00000001;
  RIM_TYPEHID                 = $00000002;

  RID_INPUT                   = $10000003;
  RID_HEADER                  = $10000005;

  RIDI_PREPARSEDDATA          = $20000005;
  RIDI_DEVICENAME             = $20000007;
  RIDI_DEVICEINFO             = $2000000b;

////////////////////////////////////////////////////////////////////////////////

type
  TRAWINPUTDEVICE = packed record
    usUsagePage : WORD;
    usUsage     : WORD;
    dwFlags     : DWORD;
    hwndTarget  : HWND;
  end;
  PRAWINPUTDEVICE = ^TRAWINPUTDEVICE;

  TRAWINPUTHEADER = packed record
    dwType    : DWORD;
    dwSize    : DWORD;
    hDevice   : THANDLE;
    wParam    : WPARAM;
  end;
  PRAWINPUTHEADER = ^TRAWINPUTHEADER;

  TRMBUTTONS = packed record
    case Integer of
        0:(ulButtons: ULONG);
        1:(
           usButtonFlags : SHORT;
           usButtonData  : SHORT;
          );
    end;

  TRAWMOUSE = packed record
    usFlags            : SHORT;
    RMButtons          : TRMBUTTONS;
    ulRawButtons       : ULONG;
    lLastX             : LongInt;
    lLastY             : LongInt;
    ulExtraInformation : ULONG;
  end;
  PRAWMOUSE = ^TRAWMOUSE;

  TRAWKEYBOARD = packed record
    MakeCode         : SHORT;
    Flags            : SHORT;
    Reserved         : SHORT;
    VKey             : SHORT;
    Mess             : UINT;
    ExtraInformation : ULONG;
  end;
  PRAWKEYBOARD = ^TRAWKEYBOARD;

  TRAWHID = packed record
    dwSizeHid : DWORD;
    dwCount   : DWORD;
    bRawData  : BYTE;
  end;
  PTRAWHID = ^TRAWHID;

  TRAWINPUTDATA = packed record
    case Integer of
      0:(mouse    : TRAWMOUSE   );
      1:(keyboard : TRAWKEYBOARD);
      2:(hid      : TRAWHID     );
    end;

  TRAWINPUT = packed record
      header  : TRAWINPUTHEADER;
      data    : TRAWINPUTDATA;
  end;
  PRAWINPUT = ^TRAWINPUT;

  TRID_DEVICE_INFO_MOUSE = packed record
     dwId               : DWORD;
     dwNumberOfButtons  : DWORD;
     dwSampleRate       : DWORD;
  end;
  PRID_DEVICE_INFO_MOUSE = ^TRID_DEVICE_INFO_MOUSE;

  TRID_DEVICE_INFO_KEYBOARD = packed record
     dwType : DWORD;
     dwSubType              : DWORD;
     dwKeyboardMode         : DWORD;
     dwNumberOfFunctionKeys : DWORD;
     dwNumberOfIndicators   : DWORD;
     dwNumberOfKeysTotal    : DWORD;
  end;
  PRID_DEVICE_INFO_KEYBOARD = ^TRID_DEVICE_INFO_KEYBOARD;

  TRID_DEVICE_INFO_HID  = packed record
     dwVendorId       : DWORD;
     dwProductId      : DWORD;
     dwVersionNumber  : DWORD;
     usUsagePage      : USHORT;
     usUsage          : USHORT;
     end;
  PRID_DEVICE_INFO_HID = ^TRID_DEVICE_INFO_HID;

  TRID_DEVICE_INFO = packed record
      cbSize : DWORD;
      dwType : DWORD;
      case Integer of
        0:(mouse    : TRID_DEVICE_INFO_MOUSE   );
        1:(keyboard : TRID_DEVICE_INFO_KEYBOARD);
        2:(hid      : TRID_DEVICE_INFO_HID     );
  end;
  PRID_DEVICE_INFO = ^TRID_DEVICE_INFO;

////////////////////////////////////////////////////////////////////////////////

function RegisterRawInputDevices(pRawInputDevices: Pointer;uiNumDevices,cbSize: UINT): Boolean; stdcall; external 'user32.dll';
function GetRawInputData(hRawInput: Pointer; uiCommand:UINT; pData: Pointer; pcbSize: Pointer; cbSizeHeader: UINT): UINT; stdcall; external 'user32.dll';
function GetRawInputDeviceInfoA(hDevice: THandle; uiCommand:UINT; pData: Pointer; pcbSize: Pointer): UINT; stdcall; external 'user32.dll';

////////////////////////////////////////////////////////////////////////////////

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    Rid: packed array [0..RI_NUM_DEVICE-1] of TRAWInputDevice;
    procedure WmInput(var Mess: TMessage); message WM_INPUT;
    function IntToBit(Value: Integer): String;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

////////////////////////////////////////////////////////////////////////////////

function TForm1.IntToBit(Value: Integer): String;
var
  i: integer;
begin
  for i:=31 downto 0 do
    if (Value shr i) = 1 then
      Result := Result + '1'
    else
      Result := Result + '0';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
// マウスデバイスを登録
  Rid[0].usUsagePage := $0001;
  Rid[0].usUsage     := $02;
  Rid[0].dwFlags     := RIDEV_INPUTSINK;  //0;
  Rid[0].hwndTarget  := Self.Handle;
// キーボードデバイスを登録
  Rid[1].usUsagePage := $0001;
  Rid[1].usUsage     := $06;
  Rid[1].dwFlags     := RIDEV_INPUTSINK;
  Rid[1].hwndTarget  := Self.Handle;
  RegisterRawInputDevices(@Rid, RI_NUM_DEVICE, SizeOf(TRAWInputDevice));
end;

procedure TForm1.WmInput(var Mess: TMessage);
var
  i,l: Integer;
  RI: PRAWINPUT;
  dwSize: UINT;
  lpb: PBYTE;
  DataSize: DWORD;
  HID_DATA:array [0..15] of DWORD;
  P:PByte;
  tmpX,tmpY: Integer;
  pData: Pointer;
  DevName: PChar;
  NameSize: Integer;
  DevInfo: TRID_DEVICE_INFO;
  MouInfo: TRID_DEVICE_INFO_MOUSE;
  RIMou: PRAWINPUT;
  strOut: String;
begin

  GetRawInputData(PRAWINPUT(Mess.LParam), RID_INPUT, nil, @dwSize,SizeOf(TRAWINPUTHEADER));

  if dwSize = 0 then Exit;

  DataSize := SizeOf(BYTE) * dwSize;

  GetMem(lpb,DataSize);

  try
    GetRawInputData(PRAWINPUT(Mess.LParam), RID_INPUT, lpb, @dwSize, SizeOf(TRAWINPUTHEADER));
    RI := PRAWINPUT(lpb);

    strOut := 'RAWINPUT.header.hDevice: ' + IntToStr(RI.header.hDevice);

    case RI.header.dwType of
      // マウス
      RIM_TYPEMOUSE:
            begin
              Windows.Beep(700,20); //うるさい

              strOut := strOut + #13 + 'マウス';
            
              tmpX := RI.Data.mouse.lLastX;
              if tmpX > 0 then
              begin
                tmpX := tmpX shr 16;
              end
              else
              begin
                tmpX := -(($FFFF - tmpX) shr 16);
              end;

              tmpY := RI.Data.mouse.lLastY;
              if tmpY > 0 then
              begin
                tmpY := tmpY shr 16;
              end
              else
              begin
                tmpY := -(($FFFF - tmpY) shr 16);
              end;

              GetRawInputDeviceInfoA(RI.header.hDevice, RIDI_DEVICENAME, nil, @dwSize);
              NameSize := dwSize;
              GetMem(DevName,dwSize);
              GetRawInputDeviceInfoA(RI.header.hDevice, RIDI_DEVICENAME, Pointer(DevName), @dwSize);

              DevInfo.cbSize := SizeOf(TRID_DEVICE_INFO);
              dwSize := SizeOf(TRID_DEVICE_INFO);
              GetRawInputDeviceInfoA(RI.header.hDevice, RIDI_DEVICEINFO, @DevInfo, @dwSize);
              MouInfo := TRID_DEVICE_INFO_MOUSE(DevInfo.mouse);

              GetRawInputData(PRAWINPUT(Mess.LParam), RID_HEADER, nil, @dwSize, SizeOf(TRAWINPUTHEADER));
              DataSize := SizeOf(BYTE) * dwSize;
              GetMem(pData,DataSize);
              GetRawInputData(PRAWINPUT(Mess.LParam), RID_HEADER, pData, @dwSize, SizeOf(TRAWINPUTHEADER));
              RIMou := PRAWINPUT(pData);

              strOut := strOut + #13 + 'usFlags: ' + IntToBit(RIMou.Data.mouse.usFlags) + #13
                              + 'RMButtons.ulButtons: ' + IntToBit(RI.Data.mouse.RMButtons.ulButtons) + #13
                              + 'RMButtons.usButtonFlags: ' + IntToBit(RIMou.Data.mouse.RMButtons.usButtonFlags) + #13
                              + 'RMButtons.usButtonData: ' + IntToBit(RI.Data.mouse.RMButtons.usButtonData) + #13
                              + 'ulRawButtons: ' + IntToBit(RI.Data.mouse.ulRawButtons) + #13
                              + 'lLastX: ' + IntToStr(tmpX) + #13
                              + 'lLastY: ' + IntToStr(tmpY) + #13
                              + 'ulExtraInformation: ' + IntToBit(RI.Data.mouse.ulExtraInformation) + #13
                              + 'RIDI_DEVICENAME: ' + ' CharacterCount: ' +IntToStr(NameSize) + '  Name: ' + DevName + #13
                              + 'DevInfo.dwType: ' +IntToStr(DevInfo.dwType) + #13
                              + 'MouInfo.dwId: ' +IntToStr(MouInfo.dwId) + #13
                              + 'MouInfo.dwNumberOfButtons: ' +IntToStr(MouInfo.dwNumberOfButtons) + #13
                              + 'MouInfo.dwSampleRate: ' +IntToStr(MouInfo.dwSampleRate) + #13
            end;

            
      // キーボード
      RIM_TYPEKEYBOARD:
            begin
              strOut := strOut + #13 + 'キーボード';
              strOut := strOut + #13 + Format('KeyBoard : %.2x',[RI.Data.keyboard.VKey]);
            end;

      // HID準拠デバイス
      RIM_TYPEHID:
            begin
              strOut := strOut + #13 + 'ヒューマンインターフェースデバイス';
              P := @RI.Data.hid.bRawData;
              for i:=0 to RI.Data.hid.dwCount-1 do
              begin
                HID_DATA[i] := 0;
                for l:=1 to RI.Data.hid.dwSizeHid do
                begin
                  HID_DATA[i] := (HID_DATA[i] shl 8) + P^;
                  Inc(P);
                end;
              end;

              for i:=0 to RI.Data.hid.dwCount-1 do
                strOut := strOut + #13 + Format('HID[%d] : %x',[i+1,HID_DATA[i]]);
            end;
    end;
  finally
    FreeMem(lpb,DataSize);
  end;

  Label1.Caption := strOut;

end;

end.


QUEBits  2005-12-01 07:48:46  No: 18910

(タイトルと違う質問になってしまいますが)
上のプログラムで、
GetRawInputDeviceInfoA(RI.header.hDevice, RIDI_DEVICENAME, Pointer(DevName), @dwSize);
で得た、マウスデバイスの名前(DevName)に、0の下にアンダーバーが入った文字が入っているのはなぜなのでしょうか?
どうすれば、正しく表示されるのでしょうか?
このせいで、マウス名で識別して処理しようとしてもできません。

また、
GetRawInputDeviceInfo を使おうとしてもなかったので
GetRawInputDeviceInfoA をDLLから使っているのですが、
これだと、GetRawInputDeviceInfoA がない海外のWindowsでは
逆に動かないようになってしまうと思うのです
プログラムが動く環境によって同じような働きをするDLLの名前(名前の後ろにAとかW)が違っても
統一して動くようにするにはどうすればいいのでしょうか?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加