From: "Vincas Miliƫnas" <vincas.miliunas@gmail.com>
Subject: [PATCH 3/3] user32: Added client-side raw input function implementations (try 6)
Message-Id: <4E017243.9010000@gmail.com>
Date: Wed, 22 Jun 2011 07:40:35 +0300


(see the message in the first part of the patch)

---
 dlls/user32/input.c |  402
++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 379 insertions(+), 23 deletions(-)

diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 335be1f..653dca9 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -476,68 +476,385 @@ 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 (pRawInputDeviceList == NULL)
+        {
+            *puiNumDevices = reply->num_devices;
+            result = 0;
+        }
+        else
+        {
+            result = reply->num_devices;
+        }
+    }
+    SERVER_END_REQ;
+
+    return ret ? result : (UINT)-1;
 }
 
+#define MOUSE_USAGE_PAGE    0x01
+#define MOUSE_USAGE_ID      0x02
+#define KEYBOARD_USAGE_PAGE 0x01
+#define KEYBOARD_USAGE_ID   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 == MOUSE_USAGE_PAGE && device->usUsage == MOUSE_USAGE_ID;
+        BOOL is_keyboard = device->usUsagePage == KEYBOARD_USAGE_PAGE && device->usUsage == KEYBOARD_USAGE_ID;
+        UINT flags = device->dwFlags;
+
+        if (device->usUsagePage == 0)
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            result = FALSE;
+            break;
+        }
+
+        if (flags & RIDEV_REMOVE)
+        {
+            if (device->hwndTarget != NULL)
+            {
+                SetLastError( ERROR_INVALID_PARAMETER );
+                result = FALSE;
+                break;
+            }
+
+            SERVER_START_REQ( unregister_raw_input_device )
+            {
+                req->usage_page = device->usUsagePage;
+                req->usage = device->usUsage;
+                ret = !wine_server_call_err( req );
+            }
+            SERVER_END_REQ;
+
+            if (!ret)
+            {
+                result = FALSE;
+                break;
+            }
+
+            continue;
+        }
+
+        if (flags & RIDEV_PAGEONLY && device->usUsage == 0)
+        {
+            FIXME("RIDEV_PAGEONLY support is not implemented\n");
+            if (flags & RIDEV_EXCLUDE)
+            {
+                FIXME("RIDEV_EXCLUDE support is not implemented\n");
+                if (device->hwndTarget == NULL)
+                {
+                    SetLastError( ERROR_INVALID_PARAMETER );
+                    result = FALSE;
+                    break;
+                }
+            }
+            /* Prevent from being confused with RIDEV_NOLEGACY, because
+               RIDEV_NOLEGACY is identical to RIDEV_PAGEONLY | RIDEV_EXCLUDE */
+            flags &= ~RIDEV_NOLEGACY;
+        }
+
+        if (flags & RIDEV_NOHOTKEYS && is_keyboard)
+        {
+            FIXME("RIDEV_NOHOTKEYS support is not implemented\n");
+            /* Prevent from being confused with RIDEV_CAPTUREMOUSE */
+            flags &= ~RIDEV_NOHOTKEYS;
+        }
+
+        if (flags & RIDEV_NOLEGACY && !is_mouse && !is_keyboard)
+        {
+            SetLastError( ERROR_INVALID_FLAGS );
+            result = FALSE;
+            break;
+        }
+        else if (flags & RIDEV_NOLEGACY)
+        {
+            FIXME("RIDEV_NOLEGACY support is not implemented\n");
+
+            if (flags & RIDEV_CAPTUREMOUSE && is_mouse)
+            {
+                FIXME("RIDEV_CAPTUREMOUSE support is not implemented\n");
+                if (device->hwndTarget == NULL)
+                {
+                    SetLastError( ERROR_INVALID_FLAGS );
+                    result = FALSE;
+                    break;
+                }
+            }
+            else if (flags & RIDEV_CAPTUREMOUSE && is_keyboard)
+            {
+                SetLastError( ERROR_INVALID_FLAGS );
+                result = FALSE;
+                break;
+            }
+
+            if (flags & RIDEV_APPKEYS && is_keyboard)
+            {
+                FIXME("RIDEV_APPKEYS support is not implemented\n");
+            }
+            else if (flags & RIDEV_APPKEYS && is_mouse)
+            {
+                SetLastError( ERROR_INVALID_FLAGS );
+                result = FALSE;
+                break;
+            }
+        }
+        else if (flags & RIDEV_CAPTUREMOUSE || flags & RIDEV_APPKEYS)
+        {
+            SetLastError( ERROR_INVALID_FLAGS );
+            result = FALSE;
+            break;
+        }
+
+        if (flags & RIDEV_INPUTSINK)
+        {
+            FIXME("RIDEV_INPUTSINK support is not implemented\n");
+            if (device->hwndTarget == NULL)
+            {
+                SetLastError( ERROR_INVALID_PARAMETER );
+                result = FALSE;
+                break;
+            }
+        }
+
+        if (flags & RIDEV_EXINPUTSINK)
+        {
+            FIXME("RIDEV_EXINPUTSINK support is not implemented\n");
+        }
+
+        if (flags & RIDEV_DEVNOTIFY)
+        {
+            FIXME("RIDEV_DEVNOTIFY support is not implemented\n");
+        }
+
+        SERVER_START_REQ( register_raw_input_device )
+        {
+            req->usage_page = device->usUsagePage;
+            req->usage = device->usUsage;
+            req->flags = device->dwFlags;
+            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;
+}
 
 /******************************************************************
 *		GetRawInputData (USER32.@)
 */
 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",
+    BOOL ret;
+    UINT result;
+
+    TRACE("(hRawInput=%p, uiCommand=%d, pData=%p, pcbSize=%p, cbSizeHeader=%d)\n",
             hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
 
-    return 0;
-}
+    if (cbSizeHeader != sizeof( RAWINPUTHEADER ))
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return (UINT)-1;
+    }
+    if (pcbSize == NULL)
+    {
+        SetLastError( ERROR_NOACCESS );
+        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;
+        if (pData != NULL)
+            wine_server_set_reply( req, pData, *pcbSize );
+        ret = !wine_server_call_err( req );
+        if (pData == NULL)
+        {
+            *pcbSize = reply->size;
+            result = 0;
+        }
+        else
+        {
+            result = reply->size;
+        }
+    }
+    SERVER_END_REQ;
 
+    return ret ? result : (UINT)-1;
+}
 
 /******************************************************************
 *		GetRawInputBuffer (USER32.@)
 */
 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;
 }
 
-
 /******************************************************************
 *		GetRawInputDeviceInfoA (USER32.@)
 */
 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 = wine_utf8_wcstombs( 0, buffer, ret, pData, *pcbSize );
+            if (ret2 == -1)
+            {
+                SetLastError( ERROR_INSUFFICIENT_BUFFER );
+                return (UINT)-1;
+            }
+            else if (ret2 == -2)
+            {
+                SetLastError( ERROR_INTERNAL_ERROR );
+                return (UINT)-1;
+            }
+            return ret;
+        }
+        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 (pData == NULL)
+        {
+            *pcbSize = reply->size;
+            result = 0;
+        }
+        else
+        {
+            result = reply->size;
+        }
+    }
+    SERVER_END_REQ;
+
+    return ret ? result : (UINT)-1;
 }
 
 
@@ -546,9 +863,41 @@ 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 (pRawInputDevices == NULL)
+        {
+            *puiNumDevices = reply->num_devices;
+            result = 0;
+        }
+        else
+        {
+            result = reply->num_devices;
+        }
+    }
+    SERVER_END_REQ;
+
+    return ret ? result : (UINT)-1;
 }
 
 
@@ -557,11 +906,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.@)