Skip to content

Instantly share code, notes, and snippets.

@martinjlowm
Created July 20, 2012 21:05
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinjlowm/3153221 to your computer and use it in GitHub Desktop.
Save martinjlowm/3153221 to your computer and use it in GitHub Desktop.
Raw input patch for Wine 1.5.9 '(UINT)-1 -> result'
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 1ffce8d..9f498eb 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -476,23 +476,229 @@ BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii)
*/
UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize)
{
- FIXME("(pRawInputDeviceList=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDeviceList, puiNumDevices, cbSize);
+ BOOL ret = FALSE;
+ UINT result;
- if(pRawInputDeviceList)
- memset(pRawInputDeviceList, 0, sizeof *pRawInputDeviceList);
- *puiNumDevices = 0;
- return 0;
+ TRACE("(pRawInputDeviceList=%p, puiNumDevices=%p, cbSize=%d)\n", pRawInputDeviceList, puiNumDevices, cbSize);
+
+ if (cbSize != sizeof( RAWINPUTDEVICELIST ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return (UINT)-1;
+ }
+ if (puiNumDevices == NULL)
+ {
+ SetLastError( ERROR_NOACCESS );
+ return (UINT)-1;
+ }
+
+ SERVER_START_REQ( get_raw_input_device_list )
+ {
+ req->report_size_only = pRawInputDeviceList == NULL;
+ if (pRawInputDeviceList != NULL)
+ wine_server_set_reply( req, pRawInputDeviceList, *puiNumDevices * sizeof( RAWINPUTDEVICELIST ) );
+ ret = !wine_server_call_err( req );
+ if (!ret || pRawInputDeviceList == NULL)
+ {
+ *puiNumDevices = reply->num_devices;
+ result = 0;
+ }
+ else
+ result = reply->num_devices;
+ }
+ SERVER_END_REQ;
+
+ return ret ? result : (UINT)-1;
}
+#define HID_USAGE_PAGE_GENERIC ((unsigned short)0x01)
+#define HID_USAGE_GENERIC_MOUSE ((unsigned short)0x02)
+#define HID_USAGE_GENERIC_KEYBOARD ((unsigned short)0x06)
/******************************************************************
* RegisterRawInputDevices (USER32.@)
*/
BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize)
{
- FIXME("(pRawInputDevices=%p, uiNumDevices=%d, cbSize=%d) stub!\n", pRawInputDevices, uiNumDevices, cbSize);
+ BOOL ret, result = TRUE;
+ UINT i;
- return TRUE;
+ TRACE("(pRawInputDevices=%p, uiNumDevices=%d, cbSize=%d)\n", pRawInputDevices, uiNumDevices, cbSize);
+
+ if (pRawInputDevices == NULL || uiNumDevices == 0 || cbSize != sizeof( RAWINPUTDEVICE ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ for (i = 0; i < uiNumDevices; i += 1)
+ {
+ RAWINPUTDEVICE *device = &pRawInputDevices[i];
+ BOOL is_mouse = device->usUsagePage == HID_USAGE_PAGE_GENERIC &&
+ device->usUsage == HID_USAGE_GENERIC_MOUSE;
+ BOOL is_keyboard = device->usUsagePage == HID_USAGE_PAGE_GENERIC &&
+ device->usUsage == HID_USAGE_GENERIC_KEYBOARD;
+ UINT device_flags = device->dwFlags, registration_flags = 0;
+
+ if (device->usUsagePage == 0)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+
+ /* RIDEV_* values can overlap, therefore we need to remove confirmed cases */
+
+ if ((device_flags & RIDEV_REMOVE) == RIDEV_REMOVE)
+ {
+ if (device->hwndTarget != NULL)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+ device_flags &= ~RIDEV_REMOVE;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_REMOVE;
+ }
+
+ if ((device_flags & RIDEV_NOHOTKEYS) == RIDEV_NOHOTKEYS && is_keyboard)
+ {
+ FIXME("RIDEV_NOHOTKEYS support is not implemented\n");
+ device_flags &= ~RIDEV_NOHOTKEYS;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_NOHOTKEYS;
+ }
+
+ if ((device_flags & RIDEV_NOLEGACY) == RIDEV_NOLEGACY && !is_mouse && !is_keyboard)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+ else if ((device_flags & RIDEV_NOLEGACY) == RIDEV_NOLEGACY)
+ {
+ device_flags &= ~RIDEV_NOLEGACY;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_NOLEGACY;
+
+ if ((device_flags & RIDEV_CAPTUREMOUSE) == RIDEV_CAPTUREMOUSE && is_mouse)
+ {
+ FIXME("RIDEV_CAPTUREMOUSE support is not implemented\n");
+ if (device->hwndTarget == NULL)
+ {
+ SetLastError( ERROR_INVALID_FLAGS );
+ result = FALSE;
+ break;
+ }
+ device_flags &= ~RIDEV_CAPTUREMOUSE;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_CAPTUREMOUSE;
+ }
+ /* RIDEV_CAPTUREMOUSE && is_keyboard is not possible, because
+ RIDEV_CAPTUREMOUSE == RIDEV_NOHOTKEYS */
+
+ if ((device_flags & RIDEV_APPKEYS) == RIDEV_APPKEYS && is_keyboard)
+ {
+ FIXME("RIDEV_APPKEYS support is not implemented\n");
+ device_flags &= ~RIDEV_APPKEYS;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_APPKEYS;
+ }
+ else if ((device_flags & RIDEV_APPKEYS) == RIDEV_APPKEYS && is_mouse)
+ {
+ SetLastError( ERROR_INVALID_FLAGS );
+ result = FALSE;
+ break;
+ }
+ }
+ else if ((device_flags & RIDEV_CAPTUREMOUSE) == RIDEV_CAPTUREMOUSE ||
+ (device_flags & RIDEV_APPKEYS) == RIDEV_APPKEYS)
+ {
+ SetLastError( ERROR_INVALID_FLAGS );
+ result = FALSE;
+ break;
+ }
+
+ if ((device_flags & RIDEV_PAGEONLY) == RIDEV_PAGEONLY && device->usUsage == 0)
+ {
+ device_flags &= ~RIDEV_PAGEONLY;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_PAGEONLY;
+ }
+ else if (((device_flags & RIDEV_PAGEONLY) == RIDEV_PAGEONLY && device->usUsage != 0) ||
+ ((device_flags & RIDEV_PAGEONLY) != RIDEV_PAGEONLY && device->usUsage == 0))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+
+ if ((device_flags & RIDEV_EXCLUDE) == RIDEV_EXCLUDE)
+ {
+ if (device->hwndTarget != NULL)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+ device_flags &= ~RIDEV_EXCLUDE;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_EXCLUDE;
+ }
+
+ if ((device_flags & RIDEV_INPUTSINK) == RIDEV_INPUTSINK)
+ {
+ FIXME("RIDEV_INPUTSINK support is not implemented\n");
+ if (device->hwndTarget == NULL)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+ device_flags &= ~RIDEV_INPUTSINK;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_INPUTSINK;
+ }
+
+ if ((device_flags & RIDEV_EXINPUTSINK) == RIDEV_EXINPUTSINK)
+ {
+ FIXME("RIDEV_EXINPUTSINK support is not implemented\n");
+ if (device->hwndTarget == NULL)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ result = FALSE;
+ break;
+ }
+ device_flags &= ~RIDEV_EXINPUTSINK;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_EXINPUTSINK;
+ }
+
+ if ((device_flags & RIDEV_DEVNOTIFY) == RIDEV_DEVNOTIFY)
+ {
+ FIXME("RIDEV_DEVNOTIFY support is not implemented\n");
+ device_flags &= ~RIDEV_DEVNOTIFY;
+ registration_flags |= REGISTER_RAW_INPUT_DEVICE_DEVNOTIFY;
+ }
+
+ /* If anything is left, it's invalid */
+ if (device_flags)
+ {
+ SetLastError( ERROR_INVALID_FLAGS );
+ result = FALSE;
+ break;
+ }
+
+ SERVER_START_REQ( register_raw_input_device )
+ {
+ req->usage_page = device->usUsagePage;
+ req->usage = device->usUsage;
+ req->flags = registration_flags;
+ req->target_window = wine_server_user_handle( device->hwndTarget );
+ ret = !wine_server_call_err( req );
+ }
+ SERVER_END_REQ;
+
+ if (!ret)
+ {
+ result = FALSE;
+ break;
+ }
+ }
+
+ return result;
}
@@ -501,10 +707,43 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(PRAWINPUTDEVICE pRawInputD
*/
UINT WINAPI GetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
{
- FIXME("(hRawInput=%p, uiCommand=%d, pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n",
- hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
-
- return 0;
+ BOOL ret;
+ UINT result;
+
+ TRACE("(hRawInput=%p, uiCommand=%d, pData=%p, pcbSize=%p, cbSizeHeader=%d)\n",
+ hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
+
+ if (cbSizeHeader != sizeof( RAWINPUTHEADER ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return (UINT)-1;
+ }
+
+ SERVER_START_REQ( get_raw_input_data )
+ {
+ req->handle = wine_server_user_handle( hRawInput );
+ req->command = uiCommand;
+ req->report_size_only = pData == NULL || pcbSize == NULL;
+ if (pData != NULL && pcbSize != NULL)
+ wine_server_set_reply( req, pData, *pcbSize );
+ ret = !wine_server_call_err( req );
+ if ((!ret || pData == NULL) && pcbSize != NULL)
+ {
+ *pcbSize = reply->size;
+ result = 0;
+ }
+ else
+ result = reply->size;
+ }
+ SERVER_END_REQ;
+
+ /* Error for an invalid handle is checked before checking if pcbSize is NULL on windows */
+ if (ret && pcbSize != NULL)
+ return result;
+ else if (ret && pcbSize == NULL)
+ SetLastError( ERROR_NOACCESS );
+
+ return result;
}
@@ -513,8 +752,18 @@ UINT WINAPI GetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, P
*/
UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
{
- FIXME("(pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n", pData, pcbSize, cbSizeHeader);
+ TRACE("(pData=%p, pcbSize=%p, cbSizeHeader=%d)\n", pData, pcbSize, cbSizeHeader);
+
+ if (pcbSize == NULL || cbSizeHeader != sizeof( RAWINPUTHEADER ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return (UINT)-1;
+ }
+
+ /* Since every raw input data entry is mapped to WM_INPUT one-to-one,
+ returning anything would make the data points to be processed twice */
+ *pcbSize = 0;
return 0;
}
@@ -524,20 +773,91 @@ UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize,
*/
UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
{
- FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);
+ TRACE("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p)\n", hDevice, uiCommand, pData, pcbSize);
- return 0;
-}
+ if (pcbSize == NULL)
+ {
+ SetLastError( ERROR_NOACCESS );
+ return (UINT)-1;
+ }
+ if (uiCommand == RIDI_DEVICENAME && pData != NULL)
+ {
+ WCHAR buffer[256];
+ UINT size = 256;
+ const UINT ret = GetRawInputDeviceInfoW( hDevice, uiCommand, buffer, &size );
+ /* ret is the character count */
+ if (ret == (UINT)-1)
+ {
+ return ret;
+ }
+ else if (ret > 0 && *pcbSize >= ret)
+ {
+ const int ret2 = WideCharToMultiByte( CP_ACP, 0, buffer, ret, pData, *pcbSize, NULL, NULL );
+ return ret2 ? ret2 : (UINT)-1;
+ }
+ else if (ret > 0)
+ {
+ *pcbSize = ret;
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return (UINT)-1;
+ }
+ else
+ {
+ *pcbSize = size;
+ return ret;
+ }
+ }
+ else
+ return GetRawInputDeviceInfoW( hDevice, uiCommand, pData, pcbSize );
+}
/******************************************************************
* GetRawInputDeviceInfoW (USER32.@)
*/
UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
{
- FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);
+ BOOL ret;
+ UINT result, size_in_bytes;
- return 0;
+ TRACE("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p)\n", hDevice, uiCommand, pData, pcbSize);
+
+ if (pcbSize == NULL)
+ {
+ SetLastError( ERROR_NOACCESS );
+ return (UINT)-1;
+ }
+ if (uiCommand == RIDI_DEVICEINFO && pData != NULL)
+ {
+ RID_DEVICE_INFO *info = (RID_DEVICE_INFO *)pData;
+ if (info->cbSize != sizeof( RID_DEVICE_INFO ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return (UINT)-1;
+ }
+ }
+
+ size_in_bytes = uiCommand == RIDI_DEVICENAME ? *pcbSize * sizeof( WCHAR ) : *pcbSize;
+
+ SERVER_START_REQ( get_raw_input_device_info )
+ {
+ req->handle = wine_server_user_handle( hDevice );
+ req->command = uiCommand;
+ req->report_size_only = pData == NULL;
+ if (pData != NULL)
+ wine_server_set_reply( req, pData, size_in_bytes );
+ ret = !wine_server_call_err( req );
+ if (!ret || pData == NULL)
+ {
+ *pcbSize = reply->size;
+ result = 0;
+ }
+ else
+ result = reply->size;
+ }
+ SERVER_END_REQ;
+
+ return ret ? result : (UINT)-1;
}
@@ -546,9 +866,39 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData,
*/
UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize)
{
- FIXME("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDevices, puiNumDevices, cbSize);
+ BOOL ret = FALSE;
+ UINT result;
- return 0;
+ TRACE("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d)\n", pRawInputDevices, puiNumDevices, cbSize);
+
+ if (cbSize != sizeof( RAWINPUTDEVICE ))
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return (UINT)-1;
+ }
+ if (puiNumDevices == NULL)
+ {
+ SetLastError( ERROR_NOACCESS );
+ return (UINT)-1;
+ }
+
+ SERVER_START_REQ( get_registered_raw_input_devices )
+ {
+ req->report_size_only = pRawInputDevices == NULL;
+ if (pRawInputDevices != NULL)
+ wine_server_set_reply( req, pRawInputDevices, *puiNumDevices * sizeof( RAWINPUTDEVICE ) );
+ ret = !wine_server_call_err( req );
+ if (!ret || pRawInputDevices == NULL)
+ {
+ *puiNumDevices = reply->num_devices;
+ result = 0;
+ }
+ else
+ result = reply->num_devices;
+ }
+ SERVER_END_REQ;
+
+ return ret ? result : (UINT)-1;
}
@@ -557,11 +907,18 @@ UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT
*/
LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput, INT nInput, UINT cbSizeHeader)
{
- FIXME("(paRawInput=%p, nInput=%d, cbSizeHeader=%d) stub!\n", *paRawInput, nInput, cbSizeHeader);
+ TRACE("(paRawInput=%p, nInput=%d, cbSizeHeader=%d)\n", *paRawInput, nInput, cbSizeHeader);
- return 0;
-}
+ if (cbSizeHeader != sizeof( RAWINPUTHEADER ))
+ {
+ /* Windows does not set last error code */
+ return ERROR_INVALID_PARAMETER;
+ }
+ /* The supplied raw input entries can still be retrieved, so they will have to be released later */
+
+ return S_OK;
+}
/**********************************************************************
* AttachThreadInput (USER32.@)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c
index d45edf1..86fa729 100644
--- a/dlls/user32/tests/input.c
+++ b/dlls/user32/tests/input.c
@@ -77,6 +77,18 @@ static struct {
static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t);
static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD);
+static LRESULT (WINAPI *pDefRawInputProc) (PRAWINPUT*, INT, UINT);
+static UINT (WINAPI *pGetRawInputBuffer) (PRAWINPUT, PUINT, UINT);
+static INT (WINAPI *pGetRawInputData) (HRAWINPUT, UINT, LPVOID, PUINT, UINT);
+static UINT (WINAPI *pGetRawInputDeviceInfoA) (HANDLE, UINT, LPVOID, PUINT);
+static UINT (WINAPI *pGetRawInputDeviceInfoW) (HANDLE, UINT, LPVOID, PUINT);
+static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT);
+static UINT (WINAPI *pGetRegisteredRawInputDevices) (PRAWINPUTDEVICE, PUINT, UINT);
+static BOOL (WINAPI *pRegisterRawInputDevices) (PRAWINPUTDEVICE, UINT, UINT);
+
+#define HID_USAGE_PAGE_GENERIC ((unsigned short)0x01)
+#define HID_USAGE_GENERIC_MOUSE ((unsigned short)0x02)
+#define HID_USAGE_GENERIC_KEYBOARD ((unsigned short)0x06)
#define MAXKEYEVENTS 12
#define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one
@@ -160,6 +172,14 @@ static void init_function_pointers(void)
GET_PROC(SendInput)
GET_PROC(GetMouseMovePointsEx)
+ GET_PROC(DefRawInputProc)
+ GET_PROC(GetRawInputBuffer)
+ GET_PROC(GetRawInputData)
+ GET_PROC(GetRawInputDeviceInfoA)
+ GET_PROC(GetRawInputDeviceInfoW)
+ GET_PROC(GetRawInputDeviceList)
+ GET_PROC(GetRegisteredRawInputDevices)
+ GET_PROC(RegisterRawInputDevices)
#undef GET_PROC
}
@@ -1598,6 +1618,958 @@ static void test_keyboard_layout_name(void)
ok(!strcmp(klid, "00000409"), "expected 00000409, got %s\n", klid);
}
+static void test_def_raw_input_proc(void)
+{
+ RAWINPUT *input = NULL;
+ LRESULT ret;
+
+ if (!pDefRawInputProc)
+ {
+ win_skip("DefRawInputProc is not available\n");
+ return;
+ }
+
+ ret = pDefRawInputProc(&input, 0, sizeof(RAWINPUTHEADER));
+ ok(ret == S_OK, "Given (&input, 0, sizeof), "
+ "DefRawInputProc should acknowledge that no data was provided\n");
+}
+
+static void test_get_raw_input_device_list(void)
+{
+ RAWINPUTDEVICELIST *device_list;
+ UINT ret, count, count2;
+ DWORD error;
+
+ if (!pGetRawInputDeviceList)
+ {
+ win_skip("GetRawInputDeviceList is not available\n");
+ return;
+ }
+
+ count = 0;
+ ret = pGetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST));
+ ok(ret == 0 && count >= 1, "Given (NULL, &count, sizeof), "
+ "GetRawInputDeviceList should return the number of raw input devices\n");
+
+ device_list = HeapAlloc(GetProcessHeap(), 0, count * sizeof(RAWINPUTDEVICELIST));
+ memset(device_list, 0xFF, count * sizeof(RAWINPUTDEVICELIST));
+
+ SetLastError(0xdeadbeef);
+ count2 = 0;
+ ret = pGetRawInputDeviceList(device_list, &count2, sizeof(RAWINPUTDEVICELIST));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INSUFFICIENT_BUFFER && count2 == count,
+ "Given (device_list, &count2 = 0, sizeof), GetRawInputDeviceList should return an error, "
+ "but got a wrong one: %u\n", error);
+
+ count2 = count;
+ ret = pGetRawInputDeviceList(device_list, &count2, sizeof(RAWINPUTDEVICELIST));
+ ok(ret == count && count == count2, "Given (device_list, &count2 = count, sizeof), "
+ "GetRawInputDeviceList should return the list of raw input devices\n");
+
+ ok(device_list[0].hDevice != NULL,
+ "First device should have a non-null handle\n");
+ ok(device_list[0].dwType == RIM_TYPEMOUSE || device_list[0].dwType == RIM_TYPEKEYBOARD,
+ "First device should be a mouse or a keyboard");
+
+ HeapFree(GetProcessHeap(), 0, device_list);
+}
+
+static void test_get_raw_input_device_info_w(void)
+{
+ UINT ret, size = 0, count;
+ RAWINPUTDEVICELIST *devices;
+ WCHAR buffer[1024];
+ RID_DEVICE_INFO info;
+ DWORD error;
+
+ if (!pGetRawInputDeviceInfoW || !pGetRawInputDeviceList)
+ {
+ win_skip("GetRawInputDeviceInfoW and GetRawInputDeviceList are not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputDeviceInfoW(NULL, 0, NULL, NULL);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_NOACCESS, "Given (NULL, 0, NULL, NULL), "
+ "GetRawInputDeviceInfoW should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoW(NULL, 0, NULL, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_HANDLE,
+ "Given (NULL, 0, NULL, &size), "
+ "GetRawInputDeviceInfoW should return an error, but got a wrong one: %u\n", error);
+
+ ok(pGetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) == 0,
+ "Failed to get raw input device count\n");
+ ok(count > 0, "Should have at least one raw input device available\n");
+ ok((devices = HeapAlloc(GetProcessHeap(), 0, count * sizeof(RAWINPUTDEVICELIST))) != NULL,
+ "Failed to allocate memory for devices\n");
+ ok(pGetRawInputDeviceList(devices, &count, sizeof(RAWINPUTDEVICELIST)) == count,
+ "Failed to retrieve raw input device list");
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, 0, NULL, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (hDevice, 0, NULL, &size), "
+ "GetRawInputDeviceInfoW should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INSUFFICIENT_BUFFER,
+ "Given (hDevice, RIDI_DEVICENAME, buffer, &size = 0), "
+ "GetRawInputDeviceInfoW should return an error, but got a wrong one: %u\n", error);
+
+ size = 0;
+ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, NULL, &size);
+ ok(ret == 0 && size > 0, "Given (hDevice, RIDI_DEVICENAME, NULL, &size), "
+ "GetRawInputDeviceInfoW should return the required size to retrieve the device info\n");
+
+ buffer[0] = 0;
+ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size);
+ ok(ret != (UINT)-1 && size > 0 && lstrlenW(buffer) > 5,
+ "Given (hDevice, RIDI_DEVICENAME, buffer, &size), "
+ "GetRawInputDeviceInfoW should retrieve the device name\n");
+
+ size = sizeof(RID_DEVICE_INFO);
+ info.cbSize = sizeof(RID_DEVICE_INFO);
+ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICEINFO, &info, &size);
+ ok(ret != (UINT)-1 && ret > 0 && size > 0,
+ "Given (hDevice, RIDI_DEVICEINFO, &info, &size), "
+ "GetRawInputDeviceInfoW should retrieve the device info\n");
+
+ HeapFree(GetProcessHeap(), 0, devices);
+}
+
+static void test_get_raw_input_device_info_a(void)
+{
+ UINT ret, size = 0, count;
+ RAWINPUTDEVICELIST *devices;
+ char buffer[1024];
+ RID_DEVICE_INFO info;
+ DWORD error;
+
+ if (!pGetRawInputDeviceInfoA || !pGetRawInputDeviceList)
+ {
+ win_skip("GetRawInputDeviceInfoA and GetRawInputDeviceList are not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputDeviceInfoA(NULL, 0, NULL, NULL);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_NOACCESS, "Given (NULL, 0, NULL, NULL), "
+ "GetRawInputDeviceInfoA should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoA(NULL, 0, NULL, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_HANDLE,
+ "Given (NULL, 0, NULL, &size), "
+ "GetRawInputDeviceInfoA should return an error, but got a wrong one: %u\n", error);
+
+ ok(pGetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)) == 0,
+ "Failed to get raw input device count\n");
+ ok(count > 0, "Should have at least one raw input device available\n");
+ ok((devices = HeapAlloc(GetProcessHeap(), 0, count * sizeof(RAWINPUTDEVICELIST))) != NULL,
+ "Failed to allocate memory for devices\n");
+ ok(pGetRawInputDeviceList(devices, &count, sizeof(RAWINPUTDEVICELIST)) == count,
+ "Failed to retrieve raw input device list");
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, 0, NULL, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (hDevice, 0, NULL, &size), "
+ "GetRawInputDeviceInfoA should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ size = 0;
+ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INSUFFICIENT_BUFFER,
+ "Given (hDevice, RIDI_DEVICENAME, buffer, &size = 0), "
+ "GetRawInputDeviceInfoA should return an error, but got a wrong one: %u\n", error);
+
+ size = 0;
+ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, NULL, &size);
+ ok(ret == 0 && size > 0, "Given (hDevice, RIDI_DEVICENAME, NULL, &size), "
+ "GetRawInputDeviceInfoA should return the required size to retrieve "
+ "the device info\n");
+
+ buffer[0] = 0;
+ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size);
+ ok(ret != (UINT)-1 && size > 0 && strlen(buffer) > 5,
+ "Given (hDevice, RIDI_DEVICENAME, buffer, &size), "
+ "GetRawInputDeviceInfoA should retrieve the device name\n");
+
+ size = sizeof(RID_DEVICE_INFO);
+ info.cbSize = sizeof(RID_DEVICE_INFO);
+ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICEINFO, &info, &size);
+ ok(ret != (UINT)-1 && ret > 0 && size > 0,
+ "Given (hDevice, RIDI_DEVICEINFO, &info, &size), "
+ "GetRawInputDeviceInfoA should retrieve the device info\n");
+
+ HeapFree(GetProcessHeap(), 0, devices);
+}
+
+static void test_register_raw_input_devices(void)
+{
+ RAWINPUTDEVICE device;
+ BOOL ret;
+ DWORD error;
+
+ if (!pRegisterRawInputDevices)
+ {
+ win_skip("RegisterRawInputDevices is not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(NULL, 0, 0);
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER, "Given (NULL, 0, 0), "
+ "RegisterRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(NULL, 0, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(ret == FALSE && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, 0, sizeof), "
+ "RegisterRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ device.usUsagePage = 0;
+ device.usUsage = 0;
+ device.dwFlags = 0;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 0, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{0,0,0,0}, 0, sizeof), "
+ "RegisterRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(ret == FALSE && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{0,0,0,0}, 1, sizeof), "
+ "RegisterRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,0,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to "
+ "a mouse raw input device\n");
+
+ device.dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from "
+ "a mouse raw input device\n");
+
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should return success even if already unsubscribed\n");
+
+ device.usUsagePage = 0xFF;
+ device.usUsage = 0xFF;
+ device.dwFlags = 0;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{0xFF,0xFF,0,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to a non-existing device\n");
+
+ device.dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{0xFF,0xFF,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from "
+ "a non-existing device\n");
+
+ /* Test precondition assertions of various flags */
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_REMOVE;
+ device.hwndTarget = (HWND)-1;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{1,2,RIDEV_REMOVE,-1}, 1, sizeof), "
+ "RegisterRawInputDevices should fail to unsubscribe from a device, "
+ "when hwndTarget is non-null, but got a wrong error: %u\n", error);
+
+ device.usUsage = 0xFF;
+ device.dwFlags = RIDEV_PAGEONLY;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{1,0xFF,RIDEV_PAGEONLY,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_PAGEONLY "
+ "requires usUsage to be zero, but got a wrong error: %u\n", error);
+
+ device.usUsage = 0;
+ device.dwFlags = RIDEV_EXCLUDE;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{1,0,RIDEV_EXCLUDE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_EXCLUDE "
+ "requires usUsage to be non-zero, but got a wrong error: %u\n", error);
+
+ device.usUsage = 0xFF;
+ device.dwFlags = RIDEV_NOLEGACY;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{1,0xFF,RIDEV_NOLEGACY,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_NOLEGACY is only available for "
+ "mouse or keyboard devices, but got a wrong error: %u\n", error);
+
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_INPUTSINK;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_PARAMETER,
+ "Given (&device{1,2,RIDEV_INPUTSINK,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_INPUTSINK "
+ "requires hwndTarget to be non-null, but got a wrong error: %u\n", error);
+
+ /* Since RIDEV_CAPTUREMOUSE == RIDEV_NOHOTKEYS, scope it for the mouse device */
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_CAPTUREMOUSE;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_FLAGS,
+ "Given (&device{1,2,RIDEV_CAPTUREMOUSE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_CAPTUREMOUSE "
+ "must be combined with RIDEV_NOLEGACY, but got a wrong error: %u\n", error);
+
+ device.usUsage = HID_USAGE_GENERIC_KEYBOARD;
+ device.dwFlags = RIDEV_APPKEYS;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_FLAGS,
+ "Given (&device{1,6,RIDEV_APPKEYS,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_APPKEYS "
+ "must be combined with RIDEV_NOLEGACY, but got a wrong error: %u\n", error);
+
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_NOLEGACY | RIDEV_APPKEYS;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_FLAGS,
+ "Given (&device{1,2,RIDEV_NOLEGACY|RIDEV_APPKEYS,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_APPKEYS "
+ "can be used only on a keyboard device, but got a wrong error: %u\n", error);
+
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_NOHOTKEYS;
+ device.hwndTarget = NULL;
+ SetLastError(0xdeadbeef);
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_FLAGS,
+ "Given (&device{1,2,RIDEV_NOHOTKEYS,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail, because RIDEV_NOHOTKEYS "
+ "can be used only on a keyboard device, but got a wrong error: %u\n", error);
+}
+
+static void test_get_registered_raw_input_devices(void)
+{
+ RAWINPUTDEVICE device, device2;
+ UINT ret, count;
+ BOOL ret2;
+ DWORD error;
+
+ if (!pGetRegisteredRawInputDevices || !pRegisterRawInputDevices)
+ {
+ win_skip("GetRegisteredRawInputDevices and RegisterRawInputDevices are not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRegisteredRawInputDevices(NULL, NULL, 0);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, NULL, 0), "
+ "GetRegisteredRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRegisteredRawInputDevices(NULL, NULL, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_NOACCESS, "Given (NULL, NULL, sizeof), "
+ "GetRegisteredRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRegisteredRawInputDevices(NULL, &count, 1);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, &count, 1), "
+ "GetRegisteredRawInputDevices should return an error, but got a wrong one: %u\n", error);
+
+ count = 0xdeadbeef;
+ ret = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = 0;
+ device.hwndTarget = NULL;
+ ret2 = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret2, "Given (&device{1,2,0,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to a mouse raw input device\n");
+
+ ret = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret == 0 && count == 1, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that one device is registered\n");
+
+ memset(&device2, 0xFF, sizeof(RAWINPUTDEVICE));
+ ret = pGetRegisteredRawInputDevices(&device2, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret == 1 && memcmp(&device, &device2, sizeof(RAWINPUTDEVICE)) == 0,
+ "Given (&device2, &count, sizeof), GetRegisteredRawInputDevices "
+ "should return an identical device to the one registered\n");
+
+ ret2 = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret2, "Given (&device{1,2,0,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully reregister a device\n");
+
+ memset(&device2, 0xFF, sizeof(RAWINPUTDEVICE));
+ ret = pGetRegisteredRawInputDevices(&device2, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret == 1 && memcmp(&device, &device2, sizeof(RAWINPUTDEVICE)) == 0,
+ "Given (&device2, &count, sizeof), "
+ "GetRegisteredRawInputDevices should still return one device registered\n");
+
+ device.dwFlags = RIDEV_REMOVE;
+ ret2 = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret2, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from a mouse raw input device\n");
+
+ count = 0xdeadbeef;
+ ret = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+}
+
+static void test_register_raw_input_devices_with_flags(void)
+{
+ RAWINPUTDEVICE device, devices[2];
+ BOOL ret;
+ UINT ret2, count;
+ DWORD error;
+
+ if (!pGetRegisteredRawInputDevices || !pRegisterRawInputDevices)
+ {
+ win_skip("GetRegisteredRawInputDevices and RegisterRawInputDevices are not available\n");
+ return;
+ }
+
+ /* Assert that there are not devices registered */
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Subscribe and unsubscribe from all devices in usage page */
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = 0;
+ device.dwFlags = RIDEV_PAGEONLY;
+ device.hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,0,RIDEV_PAGEONLY,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to "
+ "devices from that usage page\n");
+
+ device.dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,0,RIDEV_REMOVE|RIDEV_PAGEONLY,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from "
+ "devices from that usage page\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Should override a device exclusion with an inclusion */
+ devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[0].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[0].dwFlags = RIDEV_EXCLUDE;
+ devices[0].hwndTarget = NULL;
+ devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[1].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[1].dwFlags = 0;
+ devices[1].hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&devices{{1,2,RIDEV_EXCLUDE,0},{1,2,0,0}}, 2, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to a device\n");
+
+ devices[1].dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(&devices[1], 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from a device\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Should register a usage page and a device from that usage page,
+ unsubscribing from them separately */
+ devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[0].usUsage = 0;
+ devices[0].dwFlags = RIDEV_PAGEONLY;
+ devices[0].hwndTarget = NULL;
+ devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[1].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[1].dwFlags = 0;
+ devices[1].hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&devices{{1,0,RIDEV_PAGEONLY,0},{1,2,0,0}}, 2, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to "
+ "usage page devices and a device from that usage page\n");
+
+ devices[0].dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY;
+ ret = pRegisterRawInputDevices(&devices[0], 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE|RIDEV_PAGEONLY,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from a mouse raw input device\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 1, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that one device is registered\n");
+
+ devices[1].dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(&devices[1], 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully unsubscribe from a mouse raw input device\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Should allow to exclude a device */
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_EXCLUDE;
+ device.hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_EXCLUDE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully exclude a device from input feed\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 1, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that one device is registered\n");
+
+ device.dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&device{1,2,RIDEV_REMOVE,0}, 1, sizeof), "
+ "RegisterRawInputDevices should successfully remove the subscribtion\n");
+
+ /* Should include a usage page and exclude a device */
+ devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[0].usUsage = 0;
+ devices[0].dwFlags = RIDEV_PAGEONLY;
+ devices[0].hwndTarget = NULL;
+ devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[1].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[1].dwFlags = RIDEV_EXCLUDE;
+ devices[1].hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&devices{{1,2,RIDEV_EXCLUDE,0},{1,2,0,0}}, 2, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe to a device\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 2, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return two entries\n");
+
+ devices[0].dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY;
+ devices[1].dwFlags = RIDEV_REMOVE;
+ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&devices{{1,2,RIDEV_REMOVE|RIDEV_PAGEONLY,0},{1,2,RIDEV_REMOVE,0}}, 1, sizeof),"
+ "RegisterRawInputDevices should successfully remove the subscribtions\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Should allow to subscribe and unsubscribe in the same call */
+ devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[0].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[0].dwFlags = 0;
+ devices[0].hwndTarget = NULL;
+ devices[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ devices[1].usUsage = HID_USAGE_GENERIC_MOUSE;
+ devices[1].dwFlags = RIDEV_REMOVE;
+ devices[1].hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Given (&devices{{1,2,0,0},{1,2,RIDEV_REMOVE,0}}, 2, sizeof), "
+ "RegisterRawInputDevices should successfully subscribe and unsubscribe\n");
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ /* Test reaction to an invalid flag */
+ SetLastError(0xdeadbeef);
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = 0x80000000;
+ device.hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE));
+ error = GetLastError();
+ ok(!ret && error == ERROR_INVALID_FLAGS,
+ "Given (&device{1,2,0x80000000,0}, 1, sizeof), "
+ "RegisterRawInputDevices should fail to register a device with "
+ "invalid flags specified, but got a wrong error: %u\n", error);
+}
+
+static void test_get_raw_input_buffer(void)
+{
+ UINT ret, size;
+ DWORD error;
+
+ if (!pGetRawInputBuffer)
+ {
+ win_skip("GetRawInputBuffer is not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputBuffer(NULL, NULL, 0);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, NULL, 0), "
+ "GetRawInputBuffer should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, NULL, sizeof), "
+ "GetRawInputBuffer should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputBuffer(NULL, &size, 1);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, &size, 1), "
+ "GetRawInputBuffer should return an error, but got a wrong one: %u\n", error);
+
+ size = (UINT)-1;
+ ret = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
+ ok(ret == 0 && size == 0, "Given (NULL, &size, sizeof), "
+ "GetRawInputBuffer should that no data is buffered\n");
+}
+
+static void test_get_raw_input_data(void)
+{
+ UINT ret, count;
+ DWORD error;
+
+ if (!pGetRawInputData)
+ {
+ win_skip("GetRawInputData is not available\n");
+ return;
+ }
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputData(NULL, 0, NULL, NULL, 0);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, 0, NULL, NULL, 0), "
+ "GetRawInputData should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputData(NULL, 0, NULL, NULL, sizeof(RAWINPUTHEADER));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_HANDLE,
+ "Given (NULL, 0, NULL, NULL, sizeof), "
+ "GetRawInputData should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputData(NULL, 0, NULL, &count, 1);
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_PARAMETER,
+ "Given (NULL, 0, NULL, &count, 1), "
+ "GetRawInputData should return an error, but got a wrong one: %u\n", error);
+
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputData(NULL, 0, NULL, &count, sizeof(RAWINPUTHEADER));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_INVALID_HANDLE,
+ "Given (NULL, 0, NULL, &count, sizeof), "
+ "GetRawInputData should return an error, but got a wrong one: %u\n", error);
+}
+
+static BOOL wm_input_recieved;
+static BOOL legacy_mouse_message_recieved;
+static BOOL legacy_keyboard_message_recieved;
+
+static LRESULT CALLBACK get_raw_input_data_wnd_proc(HWND hWnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ UINT dwSize, ret2;
+ RAWINPUT *raw;
+ BOOL ret;
+ LRESULT ret3;
+ DWORD error;
+
+ legacy_mouse_message_recieved |= msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST;
+ legacy_keyboard_message_recieved |= msg >= WM_KEYFIRST && msg <= WM_KEYLAST;
+
+ switch (msg)
+ {
+ case WM_INPUT:
+ /* Now that we have a valid HRAWINPUT handle,
+ let's test the case, when &dwSize is NULL */
+ SetLastError(0xdeadbeef);
+ ret = pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, NULL,
+ sizeof(RAWINPUTHEADER));
+ error = GetLastError();
+ ok(ret == (UINT)-1 && error == ERROR_NOACCESS,
+ "Given (lParam, RID_INPUT, NULL, NULL, sizeof), "
+ "GetRawInputData should return an error, but got a wrong one: %u\n", error);
+
+ /* Test retrieving of RAWINPUT data */
+ ret2 = pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize,
+ sizeof(RAWINPUTHEADER));
+ ok(ret2 == 0, "Failed to retrieve raw input data size\n");
+ if (!(raw = HeapAlloc(GetProcessHeap(), 0, dwSize)))
+ break;
+ ret2 = pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw, &dwSize,
+ sizeof(RAWINPUTHEADER));
+ ok(ret2 == dwSize, "Failed to retrieve raw input data\n");
+ ok(raw->header.dwType == RIM_TYPEMOUSE || raw->header.dwType == RIM_TYPEKEYBOARD,
+ "Raw input data entry must be from mouse or keyboard\n");
+ ret3 = pDefRawInputProc(&raw, 1, sizeof(RAWINPUTHEADER));
+ HeapFree(GetProcessHeap(), 0, raw);
+ wm_input_recieved = TRUE;
+ return ret3;
+ }
+ return DefWindowProcA(hWnd, msg, wParam, lParam);
+}
+
+#define ID_TIMER 1
+
+static void timer_proc(HWND hParent, UINT uMsg, UINT uEventID, DWORD dwTimer)
+{
+ PostQuitMessage(0);
+}
+
+static HWND test_get_raw_input_data_simulation_setup(HANDLE hInstance, const char *class_name,
+ RAWINPUTDEVICE *device, INPUT *input, UINT input_count)
+{
+ MSG msg;
+ BOOL ret;
+
+ HWND hWnd = CreateWindowA(class_name, "GetRawInputDataTest",
+ WS_OVERLAPPEDWINDOW, 10, 10, 200, 200,
+ NULL, NULL, hInstance, NULL);
+ assert(hWnd);
+
+ ShowWindow(hWnd, SW_SHOW);
+ SetWindowPos(hWnd, HWND_TOPMOST, 10, 10, 200, 200, SWP_NOSIZE|SWP_NOMOVE);
+ SetForegroundWindow(hWnd);
+ UpdateWindow(hWnd);
+ SetFocus(hWnd);
+
+ wm_input_recieved = FALSE;
+ legacy_mouse_message_recieved = FALSE;
+ legacy_keyboard_message_recieved = FALSE;
+
+ device->hwndTarget = hWnd;
+ ret = pRegisterRawInputDevices(device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Failed to register raw input devices: %u\n", GetLastError());
+
+ pSendInput(input_count, input, sizeof(INPUT));
+
+ /* Give half a second of running time for each test to be sure all messages are processed */
+ SetTimer(hWnd, ID_TIMER, 500, (TIMERPROC)timer_proc);
+
+ while (1 == 1)
+ {
+ ret = GetMessageA(&msg, NULL, 0, 0);
+ if (!ret || ret == (BOOL)-1)
+ break;
+ TranslateMessage(&msg);
+ DispatchMessageA(&msg);
+ }
+
+ ok(ret != -1, "Error getting window message: %u\n", GetLastError());
+ ok(wm_input_recieved, "WM_INPUT was not received\n");
+
+ return hWnd;
+}
+
+static void test_get_raw_input_data_simulation_teardown(HWND hWnd, RAWINPUTDEVICE *device)
+{
+ BOOL ret;
+ UINT size, ret2;
+ DWORD count;
+ RAWINPUT *raw;
+
+ KillTimer(hWnd, ID_TIMER);
+
+ device->dwFlags = RIDEV_REMOVE | (device->usUsage == 0 ? RIDEV_PAGEONLY : 0);
+ device->hwndTarget = NULL;
+ ret = pRegisterRawInputDevices(device, 1, sizeof(RAWINPUTDEVICE));
+ ok(ret, "Failed to unregister raw input device: %u\n", GetLastError());
+
+ count = 0xdeadbeef;
+ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE));
+ ok(ret2 == 0 && count == 0, "Given (NULL, &count, sizeof), "
+ "GetRegisteredRawInputDevices should return that no devices are registered\n");
+
+ DestroyWindow(hWnd);
+
+ /* Clear raw input buffer */
+ ret2 = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
+ if (ret2 == 0 && size > 0 &&
+ (raw = HeapAlloc(GetProcessHeap(), 0, size * sizeof(RAWINPUT))))
+ {
+ pGetRawInputBuffer(raw, &size, sizeof(RAWINPUTHEADER));
+ HeapFree(GetProcessHeap(), 0, raw);
+ }
+}
+
+static void test_get_raw_input_data_simulation(void)
+{
+ HWND hWnd;
+ WNDCLASSA wclass;
+ HANDLE hInstance = GetModuleHandleA( NULL );
+ INPUT mouse_input[5], keyboard_input;
+ ATOM registration;
+ RAWINPUTDEVICE device;
+ unsigned int i;
+
+ if (!pRegisterRawInputDevices || !pGetRawInputData || !pDefRawInputProc ||
+ !pGetRawInputBuffer || !pSendInput)
+ {
+ win_skip("Functions required to perform raw input simulation are not available\n");
+ return;
+ }
+
+ wclass.lpszClassName = "GetRawInputDataTestClass";
+ wclass.style = CS_HREDRAW | CS_VREDRAW;
+ wclass.lpfnWndProc = get_raw_input_data_wnd_proc;
+ wclass.hInstance = hInstance;
+ wclass.hIcon = LoadIconA(0, IDI_APPLICATION);
+ wclass.hCursor = LoadCursorA(NULL, IDC_ARROW);
+ wclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wclass.lpszMenuName = NULL;
+ wclass.cbClsExtra = 0;
+ wclass.cbWndExtra = 0;
+ registration = RegisterClassA(&wclass);
+ assert(registration);
+
+ /* Setup fixtures */
+ device.usUsagePage = HID_USAGE_PAGE_GENERIC;
+
+ memset(&keyboard_input, 0, sizeof(keyboard_input));
+ keyboard_input.type = INPUT_KEYBOARD;
+ keyboard_input.ki.wVk = VK_SPACE;
+
+ /* Be sure to move over the window, because the absolute window position on the screen
+ depends on how desktop widgets are placed */
+ memset(&mouse_input, 0, sizeof(mouse_input));
+ mouse_input[0].type = INPUT_MOUSE;
+ mouse_input[0].mi.dx = mouse_input[0].mi.dy = 15;
+ mouse_input[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+ mouse_input[1].type = INPUT_MOUSE;
+ mouse_input[1].mi.mouseData = 0x0078;
+ mouse_input[1].mi.dwFlags = MOUSEEVENTF_WHEEL;
+ for (i = 2; i < sizeof(mouse_input) / sizeof(mouse_input[0]); i++)
+ {
+ mouse_input[i].type = INPUT_MOUSE;
+ mouse_input[i].mi.dx = mouse_input[i].mi.dy = 30;
+ mouse_input[i].mi.dwFlags = MOUSEEVENTF_MOVE;
+ }
+
+ /* Test WM_INPUT for mouse */
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = 0;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ mouse_input, 5);
+ ok(legacy_mouse_message_recieved, "Should have received legacy mouse messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+
+ /* Test WM_INPUT for keyboard */
+ device.usUsage = HID_USAGE_GENERIC_KEYBOARD;
+ device.dwFlags = 0;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ &keyboard_input, 1);
+ ok(legacy_keyboard_message_recieved, "Should have received legacy keyboard messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+
+ /* Test RIDEV_PAGEONLY using mouse */
+ device.usUsage = 0;
+ device.dwFlags = RIDEV_PAGEONLY;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ mouse_input, 5);
+ ok(legacy_mouse_message_recieved, "Should have received legacy mouse messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+
+ /* Test RIDEV_PAGEONLY using keyboard */
+ device.usUsage = 0;
+ device.dwFlags = RIDEV_PAGEONLY;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ &keyboard_input, 1);
+ ok(legacy_keyboard_message_recieved, "Should have received legacy keyboard messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+
+ /* Test RIDEV_NOLEGACY for mouse */
+ device.usUsage = HID_USAGE_GENERIC_MOUSE;
+ device.dwFlags = RIDEV_NOLEGACY;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ mouse_input, 5);
+ ok(!legacy_mouse_message_recieved, "Should have not received legacy mouse messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+
+ /* Test RIDEV_NOLEGACY for keyboard */
+ device.usUsage = HID_USAGE_GENERIC_KEYBOARD;
+ device.dwFlags = RIDEV_NOLEGACY;
+
+ hWnd = test_get_raw_input_data_simulation_setup(hInstance, wclass.lpszClassName, &device,
+ &keyboard_input, 1);
+ ok(!legacy_keyboard_message_recieved, "Should have not received legacy keyboard messages\n");
+ test_get_raw_input_data_simulation_teardown(hWnd, &device);
+}
+
START_TEST(input)
{
init_function_pointers();
@@ -1617,6 +2589,17 @@ START_TEST(input)
test_get_async_key_state();
test_keyboard_layout_name();
+ test_def_raw_input_proc();
+ test_get_raw_input_device_list();
+ test_get_raw_input_device_info_w();
+ test_get_raw_input_device_info_a();
+ test_register_raw_input_devices();
+ test_get_registered_raw_input_devices();
+ test_register_raw_input_devices_with_flags();
+ test_get_raw_input_buffer();
+ test_get_raw_input_data();
+ test_get_raw_input_data_simulation();
+
if(pGetMouseMovePointsEx)
test_GetMouseMovePointsEx();
else
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ee438b4..6399f2f 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4878,6 +4878,91 @@ struct set_suspend_context_reply
};
+
+struct get_raw_input_device_list_request
+{
+ struct request_header __header;
+ unsigned int report_size_only;
+};
+struct get_raw_input_device_list_reply
+{
+ struct reply_header __header;
+ unsigned int num_devices;
+ /* VARARG(devices,bytes); */
+ char __pad_12[4];
+};
+
+
+struct register_raw_input_device_request
+{
+ struct request_header __header;
+ unsigned short usage_page;
+ unsigned short usage;
+ unsigned int flags;
+ user_handle_t target_window;
+};
+struct register_raw_input_device_reply
+{
+ struct reply_header __header;
+};
+#define REGISTER_RAW_INPUT_DEVICE_REMOVE 0x0001
+#define REGISTER_RAW_INPUT_DEVICE_PAGEONLY 0x0002
+#define REGISTER_RAW_INPUT_DEVICE_EXCLUDE 0x0004
+#define REGISTER_RAW_INPUT_DEVICE_NOLEGACY 0x0008
+#define REGISTER_RAW_INPUT_DEVICE_NOHOTKEYS 0x0010
+#define REGISTER_RAW_INPUT_DEVICE_CAPTUREMOUSE 0x0020
+#define REGISTER_RAW_INPUT_DEVICE_APPKEYS 0x0040
+#define REGISTER_RAW_INPUT_DEVICE_INPUTSINK 0x0080
+#define REGISTER_RAW_INPUT_DEVICE_EXINPUTSINK 0x0100
+#define REGISTER_RAW_INPUT_DEVICE_DEVNOTIFY 0x0200
+
+
+struct get_registered_raw_input_devices_request
+{
+ struct request_header __header;
+ unsigned int report_size_only;
+};
+struct get_registered_raw_input_devices_reply
+{
+ struct reply_header __header;
+ unsigned int num_devices;
+ /* VARARG(devices,bytes); */
+ char __pad_12[4];
+};
+
+
+struct get_raw_input_device_info_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int command;
+ unsigned int report_size_only;
+};
+struct get_raw_input_device_info_reply
+{
+ struct reply_header __header;
+ data_size_t size;
+ /* VARARG(info,bytes); */
+ char __pad_12[4];
+};
+
+
+struct get_raw_input_data_request
+{
+ struct request_header __header;
+ user_handle_t handle;
+ unsigned int command;
+ unsigned int report_size_only;
+};
+struct get_raw_input_data_reply
+{
+ struct reply_header __header;
+ data_size_t size;
+ /* VARARG(data,bytes); */
+ char __pad_12[4];
+};
+
+
enum request
{
REQ_new_process,
@@ -5127,6 +5212,11 @@ enum request
REQ_set_cursor,
REQ_get_suspend_context,
REQ_set_suspend_context,
+ REQ_get_raw_input_device_list,
+ REQ_register_raw_input_device,
+ REQ_get_registered_raw_input_devices,
+ REQ_get_raw_input_device_info,
+ REQ_get_raw_input_data,
REQ_NB_REQUESTS
};
@@ -5381,6 +5471,11 @@ union generic_request
struct set_cursor_request set_cursor_request;
struct get_suspend_context_request get_suspend_context_request;
struct set_suspend_context_request set_suspend_context_request;
+ struct get_raw_input_device_list_request get_raw_input_device_list_request;
+ struct register_raw_input_device_request register_raw_input_device_request;
+ struct get_registered_raw_input_devices_request get_registered_raw_input_devices_request;
+ struct get_raw_input_device_info_request get_raw_input_device_info_request;
+ struct get_raw_input_data_request get_raw_input_data_request;
};
union generic_reply
{
@@ -5633,8 +5728,13 @@ union generic_reply
struct set_cursor_reply set_cursor_reply;
struct get_suspend_context_reply get_suspend_context_reply;
struct set_suspend_context_reply set_suspend_context_reply;
+ struct get_raw_input_device_list_reply get_raw_input_device_list_reply;
+ struct register_raw_input_device_reply register_raw_input_device_reply;
+ struct get_registered_raw_input_devices_reply get_registered_raw_input_devices_reply;
+ struct get_raw_input_device_info_reply get_raw_input_device_info_reply;
+ struct get_raw_input_data_reply get_raw_input_data_reply;
};
#define SERVER_PROTOCOL_VERSION 432
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/Makefile.in b/server/Makefile.in
index a2f1a52..c12b2df 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -28,6 +28,7 @@ C_SRCS = \
procfs.c \
ptrace.c \
queue.c \
+ raw_input.c \
region.c \
registry.c \
request.c \
diff --git a/server/process.c b/server/process.c
index c88c89b..3702333 100644
--- a/server/process.c
+++ b/server/process.c
@@ -48,6 +48,7 @@
#include "request.h"
#include "user.h"
#include "security.h"
+#include "raw_input.h"
/* process structure */
@@ -333,10 +334,14 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
process->desktop = 0;
process->token = NULL;
process->trace_data = 0;
+ process->raw_input_len = 0;
+ process->raw_input_index = 0;
list_init( &process->thread_list );
list_init( &process->locks );
list_init( &process->classes );
list_init( &process->dlls );
+ list_init( &process->raw_registered );
+ list_init( &process->raw_inputs );
process->start_time = current_time;
process->end_time = 0;
diff --git a/server/process.h b/server/process.h
index da51a0e..d4dc9f3 100644
--- a/server/process.h
+++ b/server/process.h
@@ -22,6 +22,7 @@
#define __WINE_SERVER_PROCESS_H
#include "object.h"
+#include "raw_input.h"
struct atom_table;
struct handle_table;
@@ -81,6 +82,10 @@ struct process
client_ptr_t peb; /* PEB address in client address space */
client_ptr_t ldt_copy; /* pointer to LDT copy in client addr space */
unsigned int trace_data; /* opaque data used by the process tracing mechanism */
+ struct list raw_registered; /* registered raw input devices */
+ struct list raw_inputs; /* queued raw inputs */
+ unsigned int raw_input_len; /* number of valid raw input event ids */
+ unsigned int raw_input_index; /* number of raw input events issued */
};
struct process_snapshot
diff --git a/server/protocol.def b/server/protocol.def
index 123f16a..f147037 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3365,3 +3365,58 @@ enum coords_relative
@REQ(set_suspend_context)
VARARG(context,context); /* thread context */
@END
+
+
+/* Get the raw input device list */
+@REQ(get_raw_input_device_list)
+ unsigned int report_size_only; /* reply only with the device count */
+@REPLY
+ unsigned int num_devices; /* number of raw input device in the system */
+ VARARG(devices,bytes); /* RAWINPUTDEVICELIST structures */
+@END
+
+/* Register a raw input device */
+@REQ(register_raw_input_device)
+ unsigned short usage_page; /* usage page of the device group to register to */
+ unsigned short usage; /* usage id of the device to register to */
+ unsigned int flags; /* configuration of the registration (see below) */
+ user_handle_t target_window; /* optional window handle to receive input messages */
+@END
+#define REGISTER_RAW_INPUT_DEVICE_REMOVE 0x0001
+#define REGISTER_RAW_INPUT_DEVICE_PAGEONLY 0x0002
+#define REGISTER_RAW_INPUT_DEVICE_EXCLUDE 0x0004
+#define REGISTER_RAW_INPUT_DEVICE_NOLEGACY 0x0008
+#define REGISTER_RAW_INPUT_DEVICE_NOHOTKEYS 0x0010
+#define REGISTER_RAW_INPUT_DEVICE_CAPTUREMOUSE 0x0020
+#define REGISTER_RAW_INPUT_DEVICE_APPKEYS 0x0040
+#define REGISTER_RAW_INPUT_DEVICE_INPUTSINK 0x0080
+#define REGISTER_RAW_INPUT_DEVICE_EXINPUTSINK 0x0100
+#define REGISTER_RAW_INPUT_DEVICE_DEVNOTIFY 0x0200
+
+/* Get the registered raw input devices */
+@REQ(get_registered_raw_input_devices)
+ unsigned int report_size_only; /* reply only with the device count */
+@REPLY
+ unsigned int num_devices; /* number of raw input device registrations */
+ VARARG(devices,bytes); /* RAWINPUTDEVICE structures */
+@END
+
+/* Get the raw input device info */
+@REQ(get_raw_input_device_info)
+ user_handle_t handle; /* raw input device handle */
+ unsigned int command; /* desired characteristic of the device */
+ unsigned int report_size_only; /* reply only with the required size to store the data */
+@REPLY
+ data_size_t size; /* size of the data about the device */
+ VARARG(info,bytes); /* string or data structure about the device */
+@END
+
+/* Get raw input data */
+@REQ(get_raw_input_data)
+ user_handle_t handle; /* raw input event handle */
+ unsigned int command; /* instruction to reply with just the header or the whole data */
+ unsigned int report_size_only; /* reply only with required size to store the data */
+@REPLY
+ data_size_t size; /* size of the data */
+ VARARG(data,bytes); /* RAWINPUTHEADER or RAWINPUT data structure */
+@END
diff --git a/server/queue.c b/server/queue.c
index 03b0e92..577126c 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -40,6 +40,7 @@
#include "process.h"
#include "request.h"
#include "user.h"
+#include "raw_input.h"
#define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
#define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
@@ -437,6 +438,12 @@ static inline int is_keyboard_msg( struct message *msg )
return (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST);
}
+/* check whether msg is a mouse message */
+static inline int is_mouse_msg( struct message *msg )
+{
+ return (msg->msg >= WM_MOUSEFIRST && msg->msg <= WM_MOUSELAST);
+}
+
/* check if message is matched by the filter */
static inline int check_msg_filter( unsigned int msg, unsigned int first, unsigned int last )
{
@@ -1455,7 +1462,10 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg
if (win != desktop->cursor.win) always_queue = 1;
desktop->cursor.win = win;
- if (!always_queue || merge_message( input, msg )) free_message( msg );
+ if ((is_keyboard_msg( msg ) && is_nolegacy_set_for_raw_input_keyboard()) ||
+ (is_mouse_msg( msg ) && is_nolegacy_set_for_raw_input_mouse()) ||
+ !always_queue || merge_message( input, msg ))
+ free_message( msg );
else
{
msg->unique_id = 0; /* will be set once we return it to the app */
@@ -2195,9 +2205,15 @@ DECL_HANDLER(send_hardware_message)
switch (req->input.type)
{
case INPUT_MOUSE:
+ queue_mouse_raw_input( req->input.mouse.flags, req->input.mouse.info,
+ req->input.mouse.data, req->input.mouse.x, req->input.mouse.y, desktop->cursor.x,
+ desktop->cursor.y, desktop->foreground_input ? desktop->foreground_input->focus : 0 );
reply->wait = queue_mouse_message( desktop, req->win, &req->input, req->flags, sender );
break;
case INPUT_KEYBOARD:
+ queue_keyboard_raw_input( req->input.kbd.flags, req->input.kbd.info,
+ req->input.kbd.vkey, req->input.kbd.scan,
+ desktop->foreground_input ? desktop->foreground_input->focus : 0 );
reply->wait = queue_keyboard_message( desktop, req->win, &req->input, req->flags, sender );
break;
case INPUT_HARDWARE:
diff --git a/server/raw_input.c b/server/raw_input.c
new file mode 100644
index 0000000..3721187
--- /dev/null
+++ b/server/raw_input.c
@@ -0,0 +1,582 @@
+/*
+ * Server-side Raw Input Handling
+ *
+ * Copyright (C) 2011 Vincas Miliūnas
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winternl.h"
+
+#include "object.h"
+#include "process.h"
+#include "request.h"
+#include "user.h"
+#include "raw_input.h"
+
+#define MOUSE_DEVICE_HANDLE ((user_handle_t)0x01)
+#define KEYBOARD_DEVICE_HANDLE ((user_handle_t)0x02)
+
+#define HID_USAGE_PAGE_GENERIC ((unsigned short)0x01)
+#define HID_USAGE_GENERIC_MOUSE ((unsigned short)0x02)
+#define HID_USAGE_GENERIC_KEYBOARD ((unsigned short)0x06)
+
+struct raw_registration
+{
+ struct list entry;
+ unsigned short usage_page;
+ unsigned short usage;
+ unsigned int flags;
+ user_handle_t target_window;
+};
+
+struct raw_input
+{
+ struct list entry;
+ unsigned int handle;
+ user_handle_t device_handle;
+ unsigned short input_usage_page;
+ unsigned short input_usage;
+ BOOL retrieved;
+ RAWINPUT raw;
+};
+
+struct raw_device
+{
+ user_handle_t handle;
+ const WCHAR *name;
+ RID_DEVICE_INFO info;
+};
+
+static const WCHAR mouse_raw_input_device_name[] =
+ {'W','I','N','E',' ','R','a','w',' ','I','n','p','u','t',' ',
+ 'M','o','u','s','e','\0'};
+static const WCHAR keyboard_raw_input_device_name[] =
+ {'W','I','N','E',' ','R','a','w',' ','I','n','p','u','t',' ',
+ 'K','e','y','b','o','a','r','d','\0'};
+
+/* standard raw input devices with typical device info values */
+static const struct raw_device raw_devices[] =
+{
+ {MOUSE_DEVICE_HANDLE, mouse_raw_input_device_name,
+ {sizeof( RID_DEVICE_INFO ), RIM_TYPEMOUSE, {.mouse = {1, 3, 100, FALSE}}}},
+ {KEYBOARD_DEVICE_HANDLE, keyboard_raw_input_device_name,
+ {sizeof( RID_DEVICE_INFO ), RIM_TYPEKEYBOARD, {.keyboard = {4, 0, 1, 12, 3, 101}}}}
+};
+#define NUM_RAW_DEVICES (sizeof( raw_devices ) / sizeof( raw_devices[0] ))
+
+/* Get the raw input device list */
+DECL_HANDLER(get_raw_input_device_list)
+{
+ unsigned int i, size_in_bytes;
+ RAWINPUTDEVICELIST *result;
+
+ reply->num_devices = NUM_RAW_DEVICES;
+ if (!reply->num_devices || req->report_size_only)
+ return;
+
+ size_in_bytes = reply->num_devices * sizeof( RAWINPUTDEVICELIST );
+ if (size_in_bytes > get_reply_max_size())
+ {
+ set_error( STATUS_BUFFER_TOO_SMALL );
+ return;
+ }
+
+ result = set_reply_data_size( size_in_bytes );
+ if (!result)
+ {
+ set_error( STATUS_NO_MEMORY );
+ return;
+ }
+
+ for (i = 0; i < reply->num_devices; i++)
+ {
+ /* Currently fake handles are provided, however they are only used to
+ identify the devices for the GetRawInputDeviceInfo function, thus it
+ should not create any undesirable side effects */
+ result[i].hDevice = (HANDLE)raw_devices[i].handle;
+ result[i].dwType = raw_devices[i].info.dwType;
+ }
+}
+
+/* Get the raw input device info */
+DECL_HANDLER(get_raw_input_device_info)
+{
+ BOOL valid = FALSE;
+ unsigned int i, size_in_bytes;
+ void *source = NULL;
+
+ for (i = 0; i < NUM_RAW_DEVICES; i++)
+ {
+ if (raw_devices[i].handle != req->handle)
+ continue;
+ valid = TRUE;
+
+ switch (req->command)
+ {
+ case RIDI_DEVICENAME:
+ /* reply->size is the character count */
+ reply->size = lstrlenW( raw_devices[i].name ) + 1;
+ source = (void *)raw_devices[i].name;
+ break;
+ case RIDI_DEVICEINFO:
+ reply->size = sizeof( RID_DEVICE_INFO );
+ source = (void *)&raw_devices[i].info;
+ break;
+ case RIDI_PREPARSEDDATA:
+ /* No preparsed data available */
+ reply->size = 0;
+ break;
+ default:
+ set_error( STATUS_INVALID_PARAMETER );
+ break;
+ }
+ if (get_error() > 0 || req->report_size_only)
+ break;
+
+ size_in_bytes = req->command == RIDI_DEVICENAME ?
+ reply->size * sizeof( WCHAR ) : reply->size;
+ if (size_in_bytes > get_reply_max_size())
+ {
+ set_error( STATUS_BUFFER_TOO_SMALL );
+ }
+ else if (size_in_bytes > 0)
+ {
+ void *target = set_reply_data_size( size_in_bytes );
+ if (!target)
+ {
+ set_error( STATUS_NO_MEMORY );
+ break;
+ }
+
+ memcpy( target, source, size_in_bytes );
+ }
+ break;
+ }
+ if (!valid)
+ set_error( STATUS_INVALID_HANDLE );
+}
+
+/* Get the registered raw input devices */
+DECL_HANDLER(get_registered_raw_input_devices)
+{
+ unsigned int index = 0, size_in_bytes;
+ struct raw_registration *registration;
+ RAWINPUTDEVICE *result;
+
+ reply->num_devices = list_count(&current->process->raw_registered);
+ if (!reply->num_devices || req->report_size_only)
+ return;
+
+ size_in_bytes = reply->num_devices * sizeof( RAWINPUTDEVICE );
+ if (size_in_bytes > get_reply_max_size())
+ {
+ set_error( STATUS_BUFFER_TOO_SMALL );
+ return;
+ }
+
+ result = set_reply_data_size( size_in_bytes );
+ if (!result)
+ {
+ set_error( STATUS_NO_MEMORY );
+ return;
+ }
+
+ LIST_FOR_EACH_ENTRY( registration, &current->process->raw_registered,
+ struct raw_registration, entry )
+ {
+ result[index].usUsagePage = registration->usage_page;
+ result[index].usUsage = registration->usage;
+ result[index].dwFlags = registration->flags;
+ result[index].hwndTarget = (HWND)registration->target_window;
+ index += 1;
+ }
+}
+
+/* Register a raw input device */
+DECL_HANDLER(register_raw_input_device)
+{
+ struct raw_registration *registration;
+ LIST_FOR_EACH_ENTRY( registration, &current->process->raw_registered,
+ struct raw_registration, entry )
+ {
+ /* * They must be on the same usage page
+ * both marked as PAGEONLY or
+ both not marked as PAGEONLY and have identical usage ids */
+ if (registration->usage_page != req->usage_page ||
+ (!(registration->flags & REGISTER_RAW_INPUT_DEVICE_PAGEONLY &&
+ req->flags & REGISTER_RAW_INPUT_DEVICE_PAGEONLY) &&
+ (registration->flags & REGISTER_RAW_INPUT_DEVICE_PAGEONLY ||
+ req->flags & REGISTER_RAW_INPUT_DEVICE_PAGEONLY ||
+ registration->usage != req->usage)))
+ continue;
+
+ if (req->flags & REGISTER_RAW_INPUT_DEVICE_REMOVE)
+ {
+ list_remove( &registration->entry );
+ free( registration );
+ return;
+ }
+
+ /* Update existing registration */
+ registration->flags = req->flags;
+ registration->target_window = req->target_window;
+ return;
+ }
+
+ if (req->flags & REGISTER_RAW_INPUT_DEVICE_REMOVE ||
+ !(registration = mem_alloc( sizeof( *registration ) )))
+ return;
+
+ registration->usage_page = req->usage_page;
+ registration->usage = req->usage;
+ registration->flags = req->flags;
+ registration->target_window = req->target_window;
+
+ list_add_tail( &current->process->raw_registered, &registration->entry );
+}
+
+/* Get raw input data */
+DECL_HANDLER(get_raw_input_data)
+{
+ void *ptr;
+ struct raw_input *queued, *input = NULL;
+
+ LIST_FOR_EACH_ENTRY( queued, &current->process->raw_inputs, struct raw_input, entry )
+ {
+ if (queued->handle == req->handle)
+ {
+ input = queued;
+ break;
+ }
+ }
+ if (!input)
+ {
+ set_error( STATUS_INVALID_HANDLE );
+ return;
+ }
+
+ if (req->command == RID_HEADER)
+ reply->size = sizeof( RAWINPUTHEADER );
+ else if (req->command == RID_INPUT)
+ reply->size = sizeof( RAWINPUT );
+ else
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+
+ if (req->report_size_only)
+ return;
+
+ if (reply->size > get_reply_max_size())
+ {
+ set_error( STATUS_BUFFER_TOO_SMALL );
+ return;
+ }
+
+ ptr = set_reply_data_size( reply->size );
+ if (!ptr)
+ {
+ set_error( STATUS_NO_MEMORY );
+ return;
+ }
+
+ memcpy( ptr, &input->raw, reply->size );
+
+ if (req->command == RID_INPUT)
+ input->retrieved = TRUE;
+}
+
+/* Remove a raw input event from the queue */
+static void remove_raw_input(struct raw_input *input)
+{
+ list_remove( &input->entry );
+ current->process->raw_input_len -= 1;
+ free( input );
+}
+
+/* Queue a raw input event */
+static void queue_raw_input(struct raw_input *input, struct raw_registration *registration,
+ user_handle_t focus)
+{
+ user_handle_t target;
+ struct raw_input *queued, *prev = NULL;
+
+ input->handle = current->process->raw_input_index++;
+
+ /* Prevent unprocessed raw input entries from being queued indefinitely */
+ if (current->process->raw_input_len == MAX_RAW_INPUT_QUEUE_LENGTH)
+ {
+ struct raw_input *head = LIST_ENTRY( list_head( &current->process->raw_inputs ), struct raw_input, entry );
+ remove_raw_input( head );
+ }
+
+ /* Select raw input events that come from this device's input subcomponent and release
+ already processed ones, except for the last one, because it can still be
+ retrieved multiple times while processing its WIM_INPUT message */
+ LIST_FOR_EACH_ENTRY( queued, &current->process->raw_inputs, struct raw_input, entry )
+ {
+ /* Scope for the particular device and it's input subcomponent */
+ if (queued->device_handle != input->device_handle ||
+ queued->input_usage_page != input->input_usage_page ||
+ queued->input_usage != input->input_usage)
+ continue;
+
+ if (!queued->retrieved)
+ break;
+
+ if (prev)
+ remove_raw_input( prev );
+
+ prev = queued;
+ }
+
+ list_add_tail( &current->process->raw_inputs, &input->entry );
+ current->process->raw_input_len += 1;
+
+ target = registration->target_window ? registration->target_window : focus;
+ if (target)
+ post_message( target, WM_INPUT, RIM_INPUT, input->handle );
+}
+
+/* Find a raw input registration, that matches given usage page/id */
+static struct raw_registration *find_registered_usage(unsigned short usage_page,
+ unsigned short usage)
+{
+ struct raw_registration *registration, *found = NULL;
+ LIST_FOR_EACH_ENTRY( registration, &current->process->raw_registered,
+ struct raw_registration, entry )
+ {
+ if (registration->usage_page != usage_page)
+ continue;
+ else if (registration->flags & REGISTER_RAW_INPUT_DEVICE_EXCLUDE &&
+ registration->usage == usage)
+ return NULL;
+ else if (registration->flags & REGISTER_RAW_INPUT_DEVICE_PAGEONLY)
+ found = registration;
+ else if (registration->usage == usage)
+ return registration;
+ }
+ return found;
+}
+
+/* Determine mouse flags */
+static unsigned int map_mouse_flags(unsigned int flags, unsigned int mouse_data)
+{
+ unsigned int result = 0;
+ if (flags & MOUSEEVENTF_LEFTDOWN)
+ result |= RI_MOUSE_LEFT_BUTTON_DOWN;
+ if (flags & MOUSEEVENTF_LEFTUP)
+ result |= RI_MOUSE_LEFT_BUTTON_UP;
+ if (flags & MOUSEEVENTF_RIGHTDOWN)
+ result |= RI_MOUSE_RIGHT_BUTTON_DOWN;
+ if (flags & MOUSEEVENTF_RIGHTUP)
+ result |= RI_MOUSE_RIGHT_BUTTON_UP;
+ if (flags & MOUSEEVENTF_MIDDLEDOWN)
+ result |= RI_MOUSE_MIDDLE_BUTTON_DOWN;
+ if (flags & MOUSEEVENTF_MIDDLEUP)
+ result |= RI_MOUSE_MIDDLE_BUTTON_UP;
+ if (flags & MOUSEEVENTF_WHEEL)
+ result |= RI_MOUSE_WHEEL;
+ if (flags & MOUSEEVENTF_HWHEEL)
+ result |= RI_MOUSE_HORIZONTAL_WHEEL;
+ if (flags & MOUSEEVENTF_XDOWN && mouse_data == XBUTTON1)
+ result |= RI_MOUSE_BUTTON_4_DOWN;
+ if (flags & MOUSEEVENTF_XUP && mouse_data == XBUTTON1)
+ result |= RI_MOUSE_BUTTON_4_UP;
+ if (flags & MOUSEEVENTF_XDOWN && mouse_data == XBUTTON2)
+ result |= RI_MOUSE_BUTTON_5_DOWN;
+ if (flags & MOUSEEVENTF_XUP && mouse_data == XBUTTON2)
+ result |= RI_MOUSE_BUTTON_5_UP;
+ return result;
+}
+
+/* Queue a mouse raw input event */
+void queue_mouse_raw_input(unsigned int flags, unsigned int info,
+ unsigned int data, unsigned int input_x, unsigned int input_y,
+ unsigned int desktop_x, unsigned int desktop_y, user_handle_t focus)
+{
+ /* We know the device handle and its input subcomponent usage page/id in advance */
+ const user_handle_t device_handle = MOUSE_DEVICE_HANDLE;
+ const unsigned short input_usage_page = HID_USAGE_PAGE_GENERIC;
+ const unsigned short input_usage = HID_USAGE_GENERIC_MOUSE;
+ struct raw_input *input;
+
+ struct raw_registration *registration = find_registered_usage( input_usage_page, input_usage );
+ if (!registration || !(input = mem_alloc( sizeof( *input ) )))
+ return;
+
+ input->device_handle = device_handle;
+ input->input_usage_page = input_usage_page;
+ input->input_usage = input_usage;
+ input->retrieved = FALSE;
+
+ input->raw.header.dwType = RIM_TYPEMOUSE;
+ input->raw.header.dwSize = sizeof( RAWINPUT );
+ input->raw.header.hDevice = (HANDLE)device_handle;
+ input->raw.header.wParam = RIM_INPUT;
+
+ if (flags & MOUSEEVENTF_MOVE && flags & MOUSEEVENTF_ABSOLUTE)
+ {
+ input->raw.data.mouse.lLastX = input_x - desktop_x;
+ input->raw.data.mouse.lLastY = input_y - desktop_y;
+ if (flags & ~(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE) &&
+ input_x == desktop_x && input_y == desktop_y)
+ flags &= ~MOUSEEVENTF_MOVE;
+ }
+ else if (flags & MOUSEEVENTF_MOVE)
+ {
+ input->raw.data.mouse.lLastX = input_x;
+ input->raw.data.mouse.lLastY = input_y;
+ }
+ else
+ {
+ input->raw.data.mouse.lLastX = 0;
+ input->raw.data.mouse.lLastY = 0;
+ }
+
+ input->raw.data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
+ input->raw.data.mouse.usButtonFlags = map_mouse_flags( flags, data );
+ if (input->raw.data.mouse.usButtonFlags & (RI_MOUSE_WHEEL | RI_MOUSE_HORIZONTAL_WHEEL))
+ input->raw.data.mouse.usButtonData = data;
+ else
+ input->raw.data.mouse.usButtonData = 0;
+ /* ulRawButtons is undocumented and hardware/drivers dependent,
+ therefore 0 is a valid value */
+ input->raw.data.mouse.ulRawButtons = 0;
+ input->raw.data.mouse.ulExtraInformation = info;
+
+ /* Filter out zero values that come after a scroll wheel event,
+ so it would be identical to windows */
+ if (!input->raw.data.mouse.usButtonFlags &&
+ !input->raw.data.mouse.lLastX && !input->raw.data.mouse.lLastY)
+ {
+ free( input );
+ return;
+ }
+
+ queue_raw_input( input, registration, focus );
+}
+
+/* Determine keyboard flags */
+static unsigned int map_keyboard_flags(unsigned int flags, unsigned int vk_code)
+{
+ unsigned int result = 0;
+
+ if (flags & KEYEVENTF_KEYUP)
+ result |= RI_KEY_BREAK;
+ else
+ result |= RI_KEY_MAKE;
+
+ /* The extended keys are placed on the right side
+ Right shift doesn't have this flag */
+ if (flags & KEYEVENTF_EXTENDEDKEY && vk_code != VK_SHIFT && vk_code != VK_RSHIFT)
+ result |= RI_KEY_E0;
+
+ return result;
+}
+
+/* Determine keyboard virtual key-code */
+static unsigned int map_keyboard_vk_code(unsigned int vk_code)
+{
+ switch (vk_code)
+ {
+ case VK_LSHIFT:
+ case VK_RSHIFT:
+ return VK_SHIFT;
+ case VK_LCONTROL:
+ case VK_RCONTROL:
+ return VK_CONTROL;
+ case VK_LMENU:
+ case VK_RMENU:
+ return VK_MENU;
+ default:
+ return vk_code;
+ }
+}
+
+/* Determine keyboard message code */
+static unsigned int map_keyboard_message_code(unsigned int flags, unsigned int vk_code)
+{
+ /* Windows use WM_SYSKEYDOWN only for alt key-press */
+ if (!(flags & KEYEVENTF_KEYUP) && (vk_code == VK_MENU || vk_code == VK_LMENU ||
+ vk_code == VK_RMENU))
+ return WM_SYSKEYDOWN;
+ else if (flags & KEYEVENTF_KEYUP)
+ return WM_KEYUP;
+ else
+ return WM_KEYDOWN;
+}
+
+/* Queue a keyboard raw input event */
+void queue_keyboard_raw_input(unsigned int flags, unsigned int info, unsigned int vk_code,
+ unsigned int scan_code, user_handle_t focus)
+{
+ /* We know the device handle and its input subcomponent usage page/id in advance */
+ const user_handle_t device_handle = KEYBOARD_DEVICE_HANDLE;
+ const unsigned short input_usage_page = HID_USAGE_PAGE_GENERIC;
+ const unsigned short input_usage = HID_USAGE_GENERIC_KEYBOARD;
+ struct raw_input *input;
+
+ struct raw_registration *registration = find_registered_usage( input_usage_page, input_usage );
+ if (!registration || !(input = mem_alloc( sizeof( *input ) )))
+ return;
+
+ input->device_handle = device_handle;
+ input->input_usage_page = input_usage_page;
+ input->input_usage = input_usage;
+ input->retrieved = FALSE;
+
+ input->raw.header.dwType = RIM_TYPEKEYBOARD;
+ input->raw.header.dwSize = sizeof( RAWINPUT );
+ input->raw.header.hDevice = (HANDLE)device_handle;
+ input->raw.header.wParam = RIM_INPUT;
+
+ input->raw.data.keyboard.MakeCode = scan_code;
+ input->raw.data.keyboard.Flags = map_keyboard_flags( flags, vk_code );
+ input->raw.data.keyboard.Reserved = 0;
+ input->raw.data.keyboard.VKey = map_keyboard_vk_code( vk_code );
+ input->raw.data.keyboard.Message = map_keyboard_message_code( flags, vk_code );
+ input->raw.data.keyboard.ExtraInformation = info;
+
+ queue_raw_input( input, registration, focus );
+}
+
+/* Check if nolegacy flag is set for a mouse device registration */
+BOOL is_nolegacy_set_for_raw_input_mouse(void)
+{
+ struct raw_registration *registration = find_registered_usage( HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE );
+ return registration ? registration->flags & REGISTER_RAW_INPUT_DEVICE_NOLEGACY : FALSE;
+}
+
+/* Check if nolegacy flag is set for a keyboard device registration */
+BOOL is_nolegacy_set_for_raw_input_keyboard(void)
+{
+ struct raw_registration *registration = find_registered_usage( HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_KEYBOARD );
+ return registration ? registration->flags & REGISTER_RAW_INPUT_DEVICE_NOLEGACY : FALSE;
+}
diff --git a/server/raw_input.h b/server/raw_input.h
new file mode 100644
index 0000000..c8cf0b1
--- /dev/null
+++ b/server/raw_input.h
@@ -0,0 +1,39 @@
+/*
+ * Server-side Raw Input Queuing Functions
+ *
+ * Copyright (C) 2011 Vincas Miliūnas
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_RAW_INPUT_H
+#define __WINE_SERVER_RAW_INPUT_H
+
+#include "wine/server_protocol.h"
+
+#define MAX_RAW_INPUT_QUEUE_LENGTH 32
+
+struct raw_input;
+
+extern void queue_mouse_raw_input(unsigned int flags, unsigned int info,
+ unsigned int data, unsigned int input_x, unsigned int input_y,
+ unsigned int desktop_x, unsigned int desktop_y, user_handle_t focus);
+extern void queue_keyboard_raw_input(unsigned int flags, unsigned int info,
+ unsigned int vk_code, unsigned int scan_code, user_handle_t focus);
+
+extern BOOL is_nolegacy_set_for_raw_input_mouse(void);
+extern BOOL is_nolegacy_set_for_raw_input_keyboard(void);
+
+#endif /* __WINE_SERVER_RAW_INPUT_H */
diff --git a/server/request.h b/server/request.h
index d2ca2f6..848997e 100644
--- a/server/request.h
+++ b/server/request.h
@@ -358,6 +358,11 @@ DECL_HANDLER(free_user_handle);
DECL_HANDLER(set_cursor);
DECL_HANDLER(get_suspend_context);
DECL_HANDLER(set_suspend_context);
+DECL_HANDLER(get_raw_input_device_list);
+DECL_HANDLER(register_raw_input_device);
+DECL_HANDLER(get_registered_raw_input_devices);
+DECL_HANDLER(get_raw_input_device_info);
+DECL_HANDLER(get_raw_input_data);
#ifdef WANT_REQUEST_HANDLERS
@@ -611,6 +616,11 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_set_cursor,
(req_handler)req_get_suspend_context,
(req_handler)req_set_suspend_context,
+ (req_handler)req_get_raw_input_device_list,
+ (req_handler)req_register_raw_input_device,
+ (req_handler)req_get_registered_raw_input_devices,
+ (req_handler)req_get_raw_input_device_info,
+ (req_handler)req_get_raw_input_data,
};
C_ASSERT( sizeof(affinity_t) == 8 );
@@ -2134,6 +2144,31 @@ C_ASSERT( sizeof(struct set_cursor_reply) == 56 );
C_ASSERT( sizeof(struct get_suspend_context_request) == 16 );
C_ASSERT( sizeof(struct get_suspend_context_reply) == 8 );
C_ASSERT( sizeof(struct set_suspend_context_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_list_request, report_size_only) == 12 );
+C_ASSERT( sizeof(struct get_raw_input_device_list_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_list_reply, num_devices) == 8 );
+C_ASSERT( sizeof(struct get_raw_input_device_list_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct register_raw_input_device_request, usage_page) == 12 );
+C_ASSERT( FIELD_OFFSET(struct register_raw_input_device_request, usage) == 14 );
+C_ASSERT( FIELD_OFFSET(struct register_raw_input_device_request, flags) == 16 );
+C_ASSERT( FIELD_OFFSET(struct register_raw_input_device_request, target_window) == 20 );
+C_ASSERT( sizeof(struct register_raw_input_device_request) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_registered_raw_input_devices_request, report_size_only) == 12 );
+C_ASSERT( sizeof(struct get_registered_raw_input_devices_request) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_registered_raw_input_devices_reply, num_devices) == 8 );
+C_ASSERT( sizeof(struct get_registered_raw_input_devices_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_info_request, handle) == 12 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_info_request, command) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_info_request, report_size_only) == 20 );
+C_ASSERT( sizeof(struct get_raw_input_device_info_request) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_device_info_reply, size) == 8 );
+C_ASSERT( sizeof(struct get_raw_input_device_info_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_data_request, handle) == 12 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_data_request, command) == 16 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_data_request, report_size_only) == 20 );
+C_ASSERT( sizeof(struct get_raw_input_data_request) == 24 );
+C_ASSERT( FIELD_OFFSET(struct get_raw_input_data_reply, size) == 8 );
+C_ASSERT( sizeof(struct get_raw_input_data_reply) == 16 );
#endif /* WANT_REQUEST_HANDLERS */
diff --git a/server/trace.c b/server/trace.c
index 37ea216..060d3fc 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3903,6 +3903,62 @@ static void dump_set_suspend_context_request( const struct set_suspend_context_r
dump_varargs_context( " context=", cur_size );
}
+static void dump_get_raw_input_device_list_request( const struct get_raw_input_device_list_request *req )
+{
+ fprintf( stderr, " report_size_only=%08x", req->report_size_only );
+}
+
+static void dump_get_raw_input_device_list_reply( const struct get_raw_input_device_list_reply *req )
+{
+ fprintf( stderr, " num_devices=%08x", req->num_devices );
+ dump_varargs_bytes( ", devices=", cur_size );
+}
+
+static void dump_register_raw_input_device_request( const struct register_raw_input_device_request *req )
+{
+ fprintf( stderr, " usage_page=%04x", req->usage_page );
+ fprintf( stderr, ", usage=%04x", req->usage );
+ fprintf( stderr, ", flags=%08x", req->flags );
+ fprintf( stderr, ", target_window=%08x", req->target_window );
+}
+
+static void dump_get_registered_raw_input_devices_request( const struct get_registered_raw_input_devices_request *req )
+{
+ fprintf( stderr, " report_size_only=%08x", req->report_size_only );
+}
+
+static void dump_get_registered_raw_input_devices_reply( const struct get_registered_raw_input_devices_reply *req )
+{
+ fprintf( stderr, " num_devices=%08x", req->num_devices );
+ dump_varargs_bytes( ", devices=", cur_size );
+}
+
+static void dump_get_raw_input_device_info_request( const struct get_raw_input_device_info_request *req )
+{
+ fprintf( stderr, " handle=%08x", req->handle );
+ fprintf( stderr, ", command=%08x", req->command );
+ fprintf( stderr, ", report_size_only=%08x", req->report_size_only );
+}
+
+static void dump_get_raw_input_device_info_reply( const struct get_raw_input_device_info_reply *req )
+{
+ fprintf( stderr, " size=%u", req->size );
+ dump_varargs_bytes( ", info=", cur_size );
+}
+
+static void dump_get_raw_input_data_request( const struct get_raw_input_data_request *req )
+{
+ fprintf( stderr, " handle=%08x", req->handle );
+ fprintf( stderr, ", command=%08x", req->command );
+ fprintf( stderr, ", report_size_only=%08x", req->report_size_only );
+}
+
+static void dump_get_raw_input_data_reply( const struct get_raw_input_data_reply *req )
+{
+ fprintf( stderr, " size=%u", req->size );
+ dump_varargs_bytes( ", data=", cur_size );
+}
+
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_get_new_process_info_request,
@@ -4151,6 +4207,11 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_cursor_request,
(dump_func)dump_get_suspend_context_request,
(dump_func)dump_set_suspend_context_request,
+ (dump_func)dump_get_raw_input_device_list_request,
+ (dump_func)dump_register_raw_input_device_request,
+ (dump_func)dump_get_registered_raw_input_devices_request,
+ (dump_func)dump_get_raw_input_device_info_request,
+ (dump_func)dump_get_raw_input_data_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -4401,6 +4462,11 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_set_cursor_reply,
(dump_func)dump_get_suspend_context_reply,
NULL,
+ (dump_func)dump_get_raw_input_device_list_reply,
+ NULL,
+ (dump_func)dump_get_registered_raw_input_devices_reply,
+ (dump_func)dump_get_raw_input_device_info_reply,
+ (dump_func)dump_get_raw_input_data_reply,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -4651,6 +4717,11 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"set_cursor",
"get_suspend_context",
"set_suspend_context",
+ "get_raw_input_device_list",
+ "register_raw_input_device",
+ "get_registered_raw_input_devices",
+ "get_raw_input_device_info",
+ "get_raw_input_data",
};
static const struct
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment