2016-08-14 1 views
0

Я пытаюсь выяснить, как получить точную информацию о перемещении мыши из API Win32 таким образом, который работает, когда мое приложение не сфокусировано. До сих пор, я попробовал три различных подхода:Получение точных дельтах движения мыши, когда приложение не находится на переднем плане

  1. Регистрация для WM_MOUSEMOVE событий через SetWindowsHookEx с WH_MOUSE_LL. Это работает, когда приложение находится в фоновом режиме, но возвращает координаты экрана, которые относительно низки. Кроме того, баллистика указателей применяется к этим значениям, делая их менее идеальными для моих целей.
  2. Вызов GetCursorPos в цикле. Это также работает в фоновом режиме, но опять же, он возвращает координаты экрана с низким разрешением и применяется ускорение указателя.
  3. Регистрация для сырого ввода через RegisterRawInputDevices, а затем просмотр для WM_INPUT событий (с вызовами GetRawInputData для фактического доступа к данным). Этот - по крайней мере, согласно документам - возвращает координаты в нативных единицах мыши, поэтому он настолько точен, насколько это возможно. К сожалению, это работает только тогда, когда приложение сфокусировано. The docs say:

    Приложение может получать данные, когда оно находится на переднем плане и когда оно находится в фоновом режиме.

    Но я не видел никакого поведения, которое подтверждает эти претензии.

Поскольку мой основной вопрос касается третьего варианта, я включил свой код для этого ниже.

Итак, как я могу получить доступ к значениям нативной мыши таким образом, который работает, даже если приложение не имеет фокуса? Есть ли дополнительная настройка, необходимая для работы №3, или есть другие варианты?

#include "stdafx.h" 
// ... 

#define MAX_LOADSTRING 100 

// Global Variables: 
HINSTANCE hInst;        // current instance 
WCHAR szTitle[MAX_LOADSTRING];     // The title bar text 
WCHAR szWindowClass[MAX_LOADSTRING];   // the main window class name 

HWND mainWindow; 

// Forward declarations of functions included in this code module: 
ATOM    MyRegisterClass(HINSTANCE hInstance); 
BOOL    InitInstance(HINSTANCE, int); 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, 
        _In_opt_ HINSTANCE hPrevInstance, 
        _In_ LPWSTR lpCmdLine, 
        _In_ int  nCmdShow) 
{ 
    UNREFERENCED_PARAMETER(hPrevInstance); 
    UNREFERENCED_PARAMETER(lpCmdLine); 

    // TODO: Place code here. 

    // Initialize global strings 
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 
    LoadStringW(hInstance, IDC_MOUSETEST, szWindowClass, MAX_LOADSTRING); 
    MyRegisterClass(hInstance); 

    // Perform application initialization: 
    if (!InitInstance (hInstance, nCmdShow)) 
    { 
     return FALSE; 
    } 

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_MOUSETEST)); 

    MSG msg; 

    // Main message loop: 
    while (GetMessage(&msg, nullptr, 0, 0)) 
    { 
     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
     { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
     } 
    } 

    return (int) msg.wParam; 
} 



// 
// FUNCTION: MyRegisterClass() 
// 
// PURPOSE: Registers the window class. 
// 
ATOM MyRegisterClass(HINSTANCE hInstance) 
{ 
    WNDCLASSEXW wcex; 

    wcex.cbSize = sizeof(WNDCLASSEX); 

    wcex.style   = CS_HREDRAW | CS_VREDRAW; 
    wcex.lpfnWndProc = WndProc; 
    wcex.cbClsExtra  = 0; 
    wcex.cbWndExtra  = 0; 
    wcex.hInstance  = hInstance; 
    wcex.hIcon   = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MOUSETEST)); 
    wcex.hCursor  = LoadCursor(nullptr, IDC_ARROW); 
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_MOUSETEST); 
    wcex.lpszClassName = szWindowClass; 
    wcex.hIconSm  = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); 

    return RegisterClassExW(&wcex); 
} 

// 
// FUNCTION: InitInstance(HINSTANCE, int) 
// 
// PURPOSE: Saves instance handle and creates main window 
// 
// COMMENTS: 
// 
//  In this function, we save the instance handle in a global variable and 
//  create and display the main program window. 
// 
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 
{ 
    hInst = hInstance; // Store instance handle in our global variable 

    mainWindow = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | RIDEV_INPUTSINK, 
     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr); 

    if (!mainWindow) 
    { 
     return FALSE; 
    } 

    ShowWindow(mainWindow, nCmdShow); 
    UpdateWindow(mainWindow); 

    // Register for raw input events 

    RAWINPUTDEVICE targetDevice = { 0x01, 0x02, 0, mainWindow }; 
    BOOL registerRawSuccess = RegisterRawInputDevices(&targetDevice, 1, sizeof(RAWINPUTDEVICE)); 

    if (!registerRawSuccess) 
     return FALSE; 

    return TRUE; 
} 

// 
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) 
// 
// PURPOSE: Processes messages for the main window. 
// 
// 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (message) 
    { 
    // ... 
    case WM_INPUT : 
     { 
      UINT dwSize = 40; 
      static BYTE lpb[40]; 

      if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 
       NULL, &dwSize, sizeof(RAWINPUTHEADER)) == -1) 
      { 
       // TODO: Handle this... something broke 
      } 

      UINT result = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 
       lpb, &dwSize, sizeof(RAWINPUTHEADER)); 

      RAWINPUT* raw = (RAWINPUT*)lpb; 

      if (raw->header.dwType == RIM_TYPEMOUSE) 
      { 
       // Use raw->data.mouse.lLastX and raw->data.mouse.lLastY 
      } 
      break; 
     } 
    // ... 
    default: 
     return DefWindowProc(hWnd, message, wParam, lParam); 
    } 
    return 0; 
} 
+0

ли параметр в 'RIDEV_INPUTSINK' флаг при регистрации для ввода сырого? –

+0

'WM_INPUT' выдается непосредственно устройством ввода на более низком уровне, где фокус ввода не применяется. Фоновые процессы получают 'WM_INPUT' просто отлично. Если вы не получаете его, вы делаете что-то неправильно. Но вы не показывали свой код. –

+0

@ JonathanPotter Да, я верю. См. Код, который я добавил в вопросе; Я мог бы легко сделать что-то не так. –

ответ

0

При использовании Raw Input API, укажите RIDEV_INPUTSINK флаг, если вы хотите получить WM_INPUT сообщения в то время как приложение работает в фоновом режиме:

Если установлено, что позволяет абоненту получить ввод , даже если вызывающий абонент не находится на переднем плане. Обратите внимание, что необходимо указать hwndTarget.

Изменить эту строку:

RAWINPUTDEVICE targetDevice = { 0x01, 0x02, 0, mainWindow }; 

Для этого:

RAWINPUTDEVICE targetDevice = { 0x01, 0x02, RIDEV_INPUTSINK, mainWindow }; 
Смежные вопросы