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 を受け取って処理するにはどうすればいいのでしょうか?
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
{
一応、誰かの役に立つかもしれないので、ソースも書いときます。
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.
(タイトルと違う質問になってしまいますが)
上のプログラムで、
GetRawInputDeviceInfoA(RI.header.hDevice, RIDI_DEVICENAME, Pointer(DevName), @dwSize);
で得た、マウスデバイスの名前(DevName)に、0の下にアンダーバーが入った文字が入っているのはなぜなのでしょうか?
どうすれば、正しく表示されるのでしょうか?
このせいで、マウス名で識別して処理しようとしてもできません。
また、
GetRawInputDeviceInfo を使おうとしてもなかったので
GetRawInputDeviceInfoA をDLLから使っているのですが、
これだと、GetRawInputDeviceInfoA がない海外のWindowsでは
逆に動かないようになってしまうと思うのです
プログラムが動く環境によって同じような働きをするDLLの名前(名前の後ろにAとかW)が違っても
統一して動くようにするにはどうすればいいのでしょうか?
ツイート | ![]() |