Конференция "WinAPI" » Перехват WM_INPUT всех окон
 
  • DelphiN! (10.05.09 14:15) [0]
    Мне необходимо определить какая из двух мышек поключенных к компьютеру в данный момент активна, нашел в интернете пример работы через RawInput. Программа замечательно работает только когда окно моей программы активно, если перейти на другое окно, программа перестает получать сообщения от мышек(WM_INPUT).
    Мне необходимо получать сообщения об активности мыши (WM_INPUT) всегда, активно мое окно или нет. Как это реализовать я не знаю ( Вот код программы :


    unit Unit1;

    interface

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

    const
     ENUMERATE_EXISTING_MICE=0;
     MAX_DEVICES=2;
     MAX_DEVICEID_LEN=2048;

    type
     TForm1 = class(TForm)
       Memo1: TMemo;
       ApplicationEvents1: TApplicationEvents;
       procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
       procedure FormCreate(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    type
     RAW_INPUT_DATA = record
       num_mice:      integer;
       AMouseHandle:  array[0..MAX_DEVICES] of THandle;
       AMouseID:      array[0..MAX_DEVICES,0..MAX_DEVICEID_LEN] of Cardinal;
       dataBuf:       Pointer;
       data_buf_size: WORD;
     end;

     TMouse_Info=record
       mouse:     integer;
       mouseData: ^RAWMOUSE;
     end;

     const
      WM_INPUT = WM_KEYFIRST-1;

    var
     Form1: TForm1;
     rid:   RAW_INPUT_DATA;
     mInfo: TMouse_Info;

    implementation

    {$R *.dfm}

    function FindMouseNum(hdevice:THandle):integer;
    var
     i,j,k:   integer;
     DevName: array[0..MAX_DEVICEID_LEN] of Cardinal;
     max:     cardinal;
    begin
     max:=2048;
     for i:=0 to rid.num_mice-1 do
       if rid.AMouseHandle[i] = hdevice then
         begin
           if rid.AMouseID[i,0] = 0 then
             GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, @rid.AmouseID[i], max);
           result:=i;
           exit;
         end;
     GetRawInputDeviceInfo(hDevice, RIDI_DEVICENAME, @DevName, max);
     for i:=0 to rid.num_mice-1 do
       begin
         k:=0;
         for j:=0 to MAX_DEVICEID_LEN do
           if DevName[j] = rid.AmouseID[i,j] then
             inc(k);
         if k >= MAX_DEVICEID_LEN then
           begin
             rid.AMouseHandle[i]:=hdevice;
             result:=i;
             exit;
           end;
       end;
     if rid.num_mice < MAX_DEVICES then
       begin
         for j:=0 to MAX_DEVICEID_LEN do
           rid.AmouseID[rid.num_mice,j]:=devName[j];
         rid.AMouseHandle[rid.num_mice]:=hDevice;
         rid.num_mice:=rid.num_mice+1;
         result:=rid.num_mice-1;
         exit;
       end;
     result:=-1;
    end;

    procedure RawInputInit;
    var
     nDevices: Cardinal;
     pRawIn:   PRAWINPUTDEVICELIST;
     hRawIn:   array[1..100] of RAWINPUTDEVICELIST;
     rawInDev: RAWINPUTDEVICE;
    begin
     rid.dataBuf:=nil;
     rid.data_buf_size:=0;
     if GetRawInputDeviceList(nil, nDevices, sizeof(RAWINPUTDEVICELIST)) <> 0 then
       showMessage('Error 1');
     pRawIn:=nil;
     pRawIn:=@hRawIn;
     if GetRawInputDeviceList(pRawIn, nDevices, sizeof(RAWINPUTDEVICELIST)) = -1 then
       showMessage('Error 2');
     rid.num_mice:=0;
     rawInDev.usUsagePage:=1;
     rawInDev.usUsage:=2;
     rawInDev.dwFlags:=0;
     rawInDev.hwndTarget:=0;
     RegisterRawInputDevices(@rawInDev,1,sizeOf(rawInDev));
    end;

    function HandleWMInput(wnd:HWND; lPar:LPARAM):TMouse_Info;
    var
     Raw:    RAWINPUT;
     dwSize: UINT;
     res:    TMouse_Info;
     hRawIn: HRAWINPUT;
     pRawIn: PRAWINPUT;
     mouse:  integer;
    begin
     res.mouse:=-1;
     res.mouseData:=nil;
     hRawIn:=lPar;
     GetRawInputData(hRawIn,RID_INPUT, nil, dwSize, sizeof(RAWINPUTHEADER));
     if dwSize = 0 then
       showMessage('Can not allocate memory');
     New(pRawIn);
     if GetRawInputData(hRawIn,RID_INPUT,pRawIn,dwSize,sizeof(RAWINPUTHEADER)) <> dwSize then
       showMessage('GetRawInputData doesn''t return correct size !');
     raw:=pRawIn^;
     res.mouse:=-1;
     if raw.header.dwType = RIM_TYPEMOUSE then
       begin
         mouse:=FindMouseNum(raw.header.hDevice);
         res.mouse:=mouse;
         res.mouseData:=@raw.mouse;
         result:=res;
       end;
    end;

    function GetInfo(wnd:HWND; lPar:LPARAM):TMouse_Info;
    begin
     result:=HandleWMInput(wnd,lpar);
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     RawInputInit;
    end;

    procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
    var
     m: TMouse_Info;
     p: TPoint;
    begin
     if msg.message = WM_INPUT then
       begin
         m:=GetInfo(msg.hwnd,msg.lParam);
         Memo1.Lines.Add('Aktivna mishka : '+intToStr(m.mouse));
         if m.mouse = 1 then
         begin
    //*** Работает мышь 1
         end
         else
         begin
           if m.mouse = 0 then
           begin
    //*** Работает мышь 0
           end;
         end;
       end;
    end;

    end.

  • Сергей М. © (10.05.09 20:44) [1]
    Ставь глоб.хук типа WH_LL_MOUSE
  • DelphiN! (11.05.09 11:01) [2]

    > Сергей М. ©   (10.05.09 20:44) [1]


    Поставил WH_MOUSE_LL хук, однако теперь функция определения мыши (HandleWMInput) перестала работать выдает ошибку : GetRawInputData doesn''t return correct size !

    Вот как я ее вызываю :


    function SysMsgProc(code : integer; wParam : word; lParam : longint) : longint; stdcall;
    var
     m: TMouse_Info;
     Msg: TMsg;
    begin
       msg := TMsg(Pointer(lParam)^);
       m:=GetInfo(msg.hwnd,msg.lParam);
       bit.Canvas.TextOut(10,10,'mouse: '+inttostr(m.mouse)+' | WND: '+inttostr(wparam)+' | Lparam: '+inttostr(lparam));
     Result:= CallNextHookEx(GlobalData^.SysHook, Code, wParam, lParam);
    end;



    в чем может быть проблемма??
  • Юрий Зотов © (11.05.09 12:29) [3]
    wParam: integer;

    wParam: word было в Win16. Об этом можно забыть.
  • DelphiN! (14.05.09 15:28) [4]

    > Юрий Зотов ©   (11.05.09 12:29) [3]


    Изменение типа результата не дало ...
  • Сергей М. © (14.05.09 16:36) [5]

    > функция определения мыши (HandleWMInput) перестала работать


    Так ты же ей теперь совсем другое передаешь параметром..

    Она у тебя ожидает HRAWINPUT, а ты ей почему-то тычешь указатель на MSLLHOOKSTRUCT, который системой передается параметром lParam при вызове хук-функции..

    Читать сюда:

    http://msdn.microsoft.com/en-us/library/ms644986(VS.85).aspx
  • DelphiN! (15.05.09 22:48) [6]

    > Сергей М. ©   (14.05.09 16:36) [5]


    А как получить HRAWINPUT в хуке на мышь?
  • Сергей М. © (16.05.09 10:10) [7]

    > как получить HRAWINPUT в хуке на мышь?


    А собссно зачем ?

    Чего тебе не хватает в структуре MSLLHOOKSTRUCT ?
  • DelphiN! (18.05.09 20:52) [8]

    > Сергей М. ©   (16.05.09 10:10) [7]
    А собссно зачем ?


    Чтобы передать его в HandleWMInput


    > ?Чего тебе не хватает в структуре MSLLHOOKSTRUCT ?


    А что нужно передать в HandleWMInput из MSLLHOOKSTRUCT чтобы процедура HandleWMInput работала правильно?
  • Сергей М. © (18.05.09 21:28) [9]
    )

    Я спросил - для ЧЕГО тебе RAW-данные мыши ?
    ЧЕГО такого тебе не хватает в MSLLHOOKSTRUCT ? Там тебе и тек.координаты, там тебе и информация о нажатиях/отпусканиях мышиных кнопок ..
  • DelphiN! (20.05.09 18:00) [10]

    > Сергей М. ©   (18.05.09 21:28) [9]


    К одному компьютеру подключен сенсорный экран как второй монитор, на основном мониторе работает оператор. Клиент щелкает по сенсорному экрану(чтобы проголосовать как его обслужил оператор хорошо или плохо), при щелчке по сенсору указатель мыши перемещается на основном мониторе так будто бы сенсорным является основной монитор и щелкнули по нему(особенность сенсорных экранов). Для этого мне необходимо определить кто произвел щелчок по экрану(сенсор или основная мышь) и если клик произвели с сенсорного монитора то перенести положение текущего положения указателя на Screen.Width по координате x и сэмулировать нажатие мыши.
     То есть RAW данные мыши мне нужны для определения кто щелкнул по экрану мышь или сенсорный экран ...
  • Сергей М. © (21.05.09 15:55) [11]

    > сенсорный экран как второй монитор, на основном мониторе
    > работает оператор


    На обоих экранах выводится одно и то же окно, которое видит и оператор и юзер ?
  • DelphiN! (22.05.09 16:26) [12]
    Нет, 2ой экран - дополнение 1го. Видят они разное. Просто у сенсорного экрана такая особенность, что если щелкают по нему то щелчок он делает на основном экране, вот и приходится извращаться. Писали производителям об этом "глюке", они сказали что решить это нельзя, а сенсорный дисплей у них рассчитан что его используют как основной монитор...
  • Сергей М. © (22.05.09 16:45) [13]

    > 2ой экран - дополнение 1го


    Что значит "дополнение" ?
  • DelphiN! (22.05.09 18:17) [14]

    > Сергей М. ©   (22.05.09 16:45) [13]


    Подключен как 2ой монитор. Изображение на них разное, на 1ом - окна оператора, на 2ом развернутое во весь экран окно для клиента с атрибутом fsStayOnTop ...
  • Сергей М. © (24.05.09 19:45) [15]
    Т.е. ты хочешь сказать, что форма 2 твоего приложения, показанная на экране сенсорного монитора, не имеет фокуса ввода (фокус ввода имеет другая форма 1 твоего же приложения, показанная на экране оператора), но тем не менее события сенсорного ввода поступают как сообщения о мышином вводе в очередь сообщений окна формы 1 ?
  • DelphiN! (27.05.09 11:41) [16]

    > Сергей М. ©   (24.05.09 19:45) [15]


    Оператор может работать с не моим окном(например с Wordом), в этот момент ни 1ая форма ни 2ая моя форма не имеет фокус. Однако в этот момент клиент может щелкнуть по экрану сенсора и мне нужно определить был ли этот щелчок с сенсора и если да, то обработать его. Однако для постоянного контроля мне нужен глобальный хук, но на данном этапе я к сожалению не могу определить индекс устройства с которого был произведен щелчок в глобальном хуке.
  • Сергей М. © (28.05.09 12:51) [17]
    Видимо, RegisterRawInputDevices следует вызывать в процедуре инициализации dll-модуля глобального WH_GETMESSAGE-хука .
  • DelphiN! (04.06.09 13:50) [18]

    > Сергей М. ©   (28.05.09 12:51) [17]


    Точно! Помогло, спасибо!
    Только теперь появилась другая проблема.
    Когда я двигаю или нажимаю 1ой или 2ой мышкой программа отличает их друг от друга,
     на как только я эмитирую нажатие мыши на 2ом мониторе программа определяет индекс устройства при имитации как -1, после основная(1ая) мышь определяется как вторая. Как решить эту проблему?
    Вот код имитации :

     SetCursorPos(X, Y);
     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)

  • MadNash © (12.08.09 15:12) [19]
    Для того, что бы окно получала WM_INPUT в неактивном состоянии надо значение rawInDev.dwFlags установить в $00000100 (RIDEV_INPUTSINK), кроме того, с помощью флагов можно даже установить фильтр по значению UsagePage и Usage.
 
Конференция "WinAPI" » Перехват WM_INPUT всех окон
Есть новые Нет новых   [134434   +28][b:0][p:0.005]