diff --git a/wine-rawinput/PKGBUILD b/wine-rawinput/PKGBUILD new file mode 100644 index 0000000..3aca78b --- /dev/null +++ b/wine-rawinput/PKGBUILD @@ -0,0 +1,158 @@ +# Lib32 Packages for Chakra, part of chakra-project.org +# +# maintainer (x86_64): Giuseppe Calà +# maintainer (x86_64): Anke Boersma + +_pkgbasename=wine +pkgname=wine-rawinput +pkgver=1.5.11 +pkgrel=2 + +_pkgbasever=${pkgver/rc/-rc} + +source=(http://ibiblio.org/pub/linux/system/emulators/$_pkgbasename/$_pkgbasename-$_pkgbasever.tar.bz2 + rawinput3.patch) +md5sums=('930485c8df59edcf0a6e3fd87cca8b39' + 'b68cad68f5cd75241e5c89b25114cf6e') + +pkgdesc="A compatibility layer for running Windows programs with RawInput patch" +url="http://www.winehq.com" +arch=(i686 x86_64) +license=(LGPL) +categories=('system') +install=wine.install + +depends=( + fontconfig lib32-fontconfig + mesa lib32-mesa + libxcursor lib32-libxcursor + libxrandr lib32-libxrandr + libxdamage lib32-libxdamage + libxxf86dga lib32-libxxf86dga + alsa-lib lib32-alsa-lib + lcms lib32-lcms + mpg123 lib32-mpg123 + openal lib32-openal + libxml2 lib32-libxml2 + libxi lib32-libxi + gettext lib32-gettext + desktop-file-utils +) + +makedepends=(autoconf ncurses bison perl fontforge flex prelink + 'gcc>=4.5.0-2' 'gcc-multilib>=4.5.0-2' + giflib lib32-giflib + libxpm lib32-libxpm + libpng lib32-libpng + libxinerama lib32-libxinerama + libxcomposite lib32-libxcomposite + libxmu lib32-libxmu + libxxf86vm lib32-libxxf86vm + libxml2 lib32-libxml2 + libxslt lib32-libxslt + libldap lib32-libldap + lcms lib32-lcms + mpg123 lib32-mpg123 + openal lib32-openal + jack lib32-jack + libcups lib32-libcups + gnutls lib32-gnutls + v4l-utils lib32-v4l-utils + alsa-lib lib32-alsa-lib + oss + samba +) + +optdepends=( + giflib lib32-giflib + libpng lib32-libpng + libldap lib32-libldap + jack lib32-jack + libcups lib32-libcups + gnutls lib32-gnutls + v4l-utils lib32-v4l-utils + oss cups + samba +) + +if [[ $CARCH == i686 ]]; then + # Strip lib32 etc. on i686 + depends=(${depends[@]/*32-*/}) + makedepends=(${makedepends[@]/*32-*/}) + makedepends=(${makedepends[@]/*-multilib*/}) + optdepends=(${optdepends[@]/*32-*/}) +fi + +provides=("wine=$pkgver") +conflicts=('wine') + +build() { + cd "$srcdir" + + # Allow ccache to work + mv $_pkgbasename-$_pkgbasever $_pkgbasename + + cd "$_pkgbasename" + patch -Np1 -i ../rawinput3.patch + ./tools/make_requests + cd "$srcdir" + # Get rid of old build dirs + rm -rf $_pkgbasename-{32,64}-build + mkdir $_pkgbasename-32-build + + # These additional CFLAGS solve FS#27662 + export CFLAGS="${CFLAGS/-D_FORTIFY_SOURCE=2/} -D_FORTIFY_SOURCE=0" + export CXXFLAGS="${CFLAGS/-D_FORTIFY_SOURCE=2/} -D_FORTIFY_SOURCE=0" + + if [[ $CARCH == x86_64 ]]; then + msg2 "Building Wine-64..." + + mkdir $_pkgbasename-64-build + cd "$srcdir/$_pkgbasename-64-build" + ../$_pkgbasename/configure \ + --prefix=/usr \ + --sysconfdir=/etc \ + --libdir=/usr/lib \ + --with-x \ + --enable-win64 + + make + + _wine32opts=( + --libdir=/usr/lib32 + --with-wine64="$srcdir/$_pkgbasename-64-build" + ) + + export PKG_CONFIG_PATH="/usr/lib32/pkgconfig" + fi + + msg2 "Building Wine-32..." + cd "$srcdir/$_pkgbasename-32-build" + ../$_pkgbasename/configure \ + --prefix=/usr \ + --sysconfdir=/etc \ + --with-x \ + "${_wine32opts[@]}" + + # These additional CFLAGS solve FS#27560 + make CFLAGS+="-mstackrealign" CXXFLAGS+="-mstackrealign" +} + +package() { + msg2 "Packaging Wine-32..." + cd "$srcdir/$_pkgbasename-32-build" + + if [[ $CARCH == i686 ]]; then + make prefix="$pkgdir/usr" install + else + make prefix="$pkgdir/usr" \ + libdir="$pkgdir/usr/lib32" \ + dlldir="$pkgdir/usr/lib32/wine" install + + msg2 "Packaging Wine-64..." + cd "$srcdir/$_pkgbasename-64-build" + make prefix="$pkgdir/usr" \ + libdir="$pkgdir/usr/lib" \ + dlldir="$pkgdir/usr/lib/wine" install + fi +} diff --git a/wine-rawinput/rawinput3.patch b/wine-rawinput/rawinput3.patch new file mode 100644 index 0000000..f8826ab --- /dev/null +++ b/wine-rawinput/rawinput3.patch @@ -0,0 +1,2828 @@ +commit f4fd76b32d6e20970fb668276de66548d9923b58 +Author: Vincas Miliūnas +Date: Mon Sep 5 18:03:55 2011 +0300 + + qwe + +diff --git a/dlls/user32/input.c b/dlls/user32/input.c +index 1ffce8d..ebf9150 100644 +--- a/dlls/user32/input.c ++++ b/dlls/user32/input.c +@@ -476,46 +476,325 @@ 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 result = TRUE; ++ UINT i, registrations_size = uiNumDevices * sizeof( struct raw_input_device_registration ); ++ struct raw_input_device_registration *registrations; + +- 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; ++ } ++ ++ registrations = HeapAlloc( GetProcessHeap(), 0, registrations_size ); ++ if (!registrations) ++ { ++ SetLastError( ERROR_NOT_ENOUGH_MEMORY ); ++ return FALSE; ++ } ++ ++ /* Construct and validate registration data */ ++ for (i = 0; i < uiNumDevices; i++) ++ { ++ 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 |= RAW_INPUT_DEVICE_FLAG_REMOVE; ++ } ++ ++ if ((device_flags & RIDEV_NOHOTKEYS) == RIDEV_NOHOTKEYS && is_keyboard) ++ { ++ FIXME("RIDEV_NOHOTKEYS support is not implemented\n"); ++ device_flags &= ~RIDEV_NOHOTKEYS; ++ registration_flags |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_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 |= RAW_INPUT_DEVICE_FLAG_EXINPUTSINK; ++ } ++ ++ if ((device_flags & RIDEV_DEVNOTIFY) == RIDEV_DEVNOTIFY) ++ { ++ FIXME("RIDEV_DEVNOTIFY support is not implemented\n"); ++ device_flags &= ~RIDEV_DEVNOTIFY; ++ registration_flags |= RAW_INPUT_DEVICE_FLAG_DEVNOTIFY; ++ } ++ ++ /* If anything is left, it's invalid */ ++ if (device_flags) ++ { ++ SetLastError( ERROR_INVALID_FLAGS ); ++ result = FALSE; ++ break; ++ } ++ ++ registrations[i].usage_page = device->usUsagePage; ++ registrations[i].usage = device->usUsage; ++ registrations[i].flags = registration_flags; ++ registrations[i].target_window = wine_server_user_handle( device->hwndTarget ); ++ } ++ ++ if (result) ++ { ++ BOOL ret; + ++ SERVER_START_REQ( register_raw_input_devices ) ++ { ++ req->count = uiNumDevices; ++ wine_server_add_data( req, registrations, registrations_size ); ++ ret = !wine_server_call_err( req ); ++ } ++ SERVER_END_REQ; ++ ++ result = ret; ++ } ++ ++ HeapFree( GetProcessHeap(), 0, registrations ); ++ ++ 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; ++ } + ++ 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; ++ req->header_size = cbSizeHeader; ++ 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 (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); ++ BOOL ret; ++ UINT result; ++ ++ TRACE("(pData=%p, pcbSize=%p, cbSizeHeader=%d)\n", pData, pcbSize, cbSizeHeader); ++ ++ if (pcbSize == NULL || cbSizeHeader != sizeof( RAWINPUTHEADER )) ++ { ++ SetLastError( ERROR_INVALID_PARAMETER ); ++ return (UINT)-1; ++ } ++ ++ SERVER_START_REQ( get_raw_input_buffer ) ++ { ++ req->report_size_only = pData == NULL; ++ req->header_size = cbSizeHeader; ++ if (pData != NULL) ++ wine_server_set_reply( req, pData, *pcbSize ); ++ ret = !wine_server_call_err( req ); ++ if (!ret || pData == NULL) ++ { ++ *pcbSize = reply->minimum_size; ++ result = 0; ++ } ++ else ++ result = reply->count; ++ } ++ SERVER_END_REQ; + +- return 0; ++ return ret ? result : (UINT)-1; + } + + +@@ -524,20 +803,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; ++ ++ 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 0; ++ return ret ? result : (UINT)-1; + } + + +@@ -546,9 +896,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; ++ ++ 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 0; ++ return ret ? result : (UINT)-1; + } + + +@@ -557,11 +937,19 @@ 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 (LRESULT)-1; ++ } + ++ /* 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..b0f495a 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 UINT (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 +@@ -159,7 +171,15 @@ static void init_function_pointers(void) + trace("GetProcAddress(%s) failed\n", #func); + + GET_PROC(SendInput) ++ GET_PROC(DefRawInputProc) + GET_PROC(GetMouseMovePointsEx) ++ 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,1169 @@ 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, raw; ++ LRESULT ret; ++ ++ if (!pDefRawInputProc) ++ { ++ win_skip("DefRawInputProc is not available\n"); ++ return; ++ } ++ ++ ret = pDefRawInputProc(&input, 0, 0); ++ ok(ret == (LRESULT)-1, "DefRawInputProc returned wrong value: expected (LRESULT)-1, got %lu\n", ret); ++ ++ ret = pDefRawInputProc(&input, 0, sizeof(RAWINPUTHEADER)); ++ ok(ret == S_OK, "DefRawInputProc returned wrong value: expected S_OK, got %lu\n", ret); ++ ++ /* Test that DefRawInputProc is ignorant of the other parameters */ ++ memset(&raw, 0xFF, sizeof(raw)); ++ input = &raw; ++ ++ ret = pDefRawInputProc(&input, 1000000, sizeof(RAWINPUTHEADER)); ++ ok(ret == S_OK, "DefRawInputProc returned wrong value: expected S_OK, got %lu\n", ret); ++ ++ ret = pDefRawInputProc(&input, -1000000, sizeof(RAWINPUTHEADER)); ++ ok(ret == S_OK, "DefRawInputProc returned wrong value: expected S_OK, got %lu\n", ret); ++} ++ ++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, "GetRawInputDeviceList returned wrong value: " ++ "expected 0, got %u\n", ret); ++ ok(count >= 1, "GetRawInputDeviceList returned incorrect number of " ++ "raw input device available: expected x >= 1, got %u\n", count); ++ ++ 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, "GetRawInputDeviceList returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INSUFFICIENT_BUFFER, "GetRawInputDeviceList returned " ++ "wrong error code: %u\n", error); ++ ok(count2 == count, "GetRawInputDeviceList returned incorrect number of devices: " ++ "expected %u, got %u\n", count, count2); ++ ++ count2 = count; ++ ret = pGetRawInputDeviceList(device_list, &count2, sizeof(RAWINPUTDEVICELIST)); ++ ok(ret == count, "GetRawInputDeviceList returned wrong value: " ++ "expected %u, got %u\n", count, ret); ++ ok(count2 == count, "GetRawInputDeviceList returned incorrect number of devices: " ++ "expected %u, got %u\n", count, count2); ++ ++ ok(device_list[0].hDevice != NULL, "First raw input device doesn't have " ++ "a non-null handle\n"); ++ ok(device_list[0].dwType == RIM_TYPEMOUSE || device_list[0].dwType == RIM_TYPEKEYBOARD, ++ "First raw input device wasn't 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[512]; ++ 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, "GetRawInputDeviceInfoW returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_NOACCESS, "GetRawInputDeviceInfoW returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoW(NULL, 0, NULL, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, ++ "GetRawInputDeviceInfoW returned wrong value: expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_HANDLE, ++ "GetRawInputDeviceInfoW returned wrong error code: %u\n", error); ++ ++ ret = pGetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); ++ ok(ret == 0, "GetRawInputDeviceList failed to return raw input device count\n"); ++ ok(count > 0, "Should have at least one raw input device available\n"); ++ ++ devices = HeapAlloc(GetProcessHeap(), 0, count * sizeof(RAWINPUTDEVICELIST)); ++ ok(devices != NULL, "Failed to allocate memory for raw input devices\n"); ++ if (!devices) ++ return; ++ ++ ret = pGetRawInputDeviceList(devices, &count, sizeof(RAWINPUTDEVICELIST)); ++ ok(ret == count, "GetRawInputDeviceList returned incorrect " ++ "number of devices: expected %u, got %u", count, ret); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, 0, NULL, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputDeviceInfoW returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputDeviceInfoW returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputDeviceInfoW returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INSUFFICIENT_BUFFER, "GetRawInputDeviceInfoW returned " ++ "wrong error code: %u\n", error); ++ ++ size = 0; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoW returned wrong value: expected 0, got %u\n", ret); ++ ok(size > 5, "GetRawInputDeviceInfoW returned wrong " ++ "device name size: expected x > 5, got %u\n", size); ++ ++ buffer[0] = 0; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size); ++ ok(ret != (UINT)-1 && ret > 0, "GetRawInputDeviceInfoW returned wrong value: " ++ "expected 0 < x < (UINT)-1, got %u\n", ret); ++ size = lstrlenW(buffer); ++ ok(size > 5, "GetRawInputDeviceInfoW returned too short device name: " ++ "expected x > 5, got %u\n", size); ++ ++ size = 0; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICEINFO, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoW returned wrong value: expected 0, got %u\n", ret); ++ ok(size == sizeof(RID_DEVICE_INFO), "GetRawInputDeviceInfoW returned " ++ "wrong device info size: expected sizeof(RID_DEVICE_INFO), got %u\n", size); ++ ++ size = sizeof(RID_DEVICE_INFO); ++ info.cbSize = sizeof(RID_DEVICE_INFO); ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_DEVICEINFO, &info, &size); ++ ok(ret == sizeof(RID_DEVICE_INFO), "GetRawInputDeviceInfoW returned wrong value: " ++ "expected sizeof(RID_DEVICE_INFO), got %u\n", ret); ++ ++ size = 0xdeadbeef; ++ ret = pGetRawInputDeviceInfoW(devices[0].hDevice, RIDI_PREPARSEDDATA, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoW returned wrong value: " ++ "expected 0, got %u\n", ret); ++ ok(size == 0, "GetRawInputDeviceInfoW returned wrong preparsed data size: " ++ "expected 0, got %u\n", size); ++ ++ HeapFree(GetProcessHeap(), 0, devices); ++} ++ ++static void test_get_raw_input_device_info_a(void) ++{ ++ UINT ret, size = 0, count; ++ RAWINPUTDEVICELIST *devices; ++ char buffer[512]; ++ 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, "GetRawInputDeviceInfoA returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_NOACCESS, "GetRawInputDeviceInfoA returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoA(NULL, 0, NULL, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, ++ "GetRawInputDeviceInfoA returned wrong value: expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_HANDLE, ++ "GetRawInputDeviceInfoA returned wrong error code: %u\n", error); ++ ++ ret = pGetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); ++ ok(ret == 0, "GetRawInputDeviceList failed to return raw input device count\n"); ++ ok(count > 0, "Should have at least one raw input device available\n"); ++ ++ devices = HeapAlloc(GetProcessHeap(), 0, count * sizeof(RAWINPUTDEVICELIST)); ++ ok(devices != NULL, "Failed to allocate memory for raw input devices\n"); ++ if (!devices) ++ return; ++ ++ ret = pGetRawInputDeviceList(devices, &count, sizeof(RAWINPUTDEVICELIST)); ++ ok(ret == count, "GetRawInputDeviceList returned incorrect " ++ "number of devices: expected %u, got %u", count, ret); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, 0, NULL, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputDeviceInfoA returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputDeviceInfoA returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ size = 0; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputDeviceInfoA returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INSUFFICIENT_BUFFER, "GetRawInputDeviceInfoA returned " ++ "wrong error code: %u\n", error); ++ ++ size = 0; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoA returned wrong value: expected 0, got %u\n", ret); ++ ok(size > 5, "GetRawInputDeviceInfoA returned wrong " ++ "device name size: expected x > 5, got %u\n", size); ++ ++ buffer[0] = 0; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICENAME, buffer, &size); ++ ok(ret != (UINT)-1 && ret > 0, "GetRawInputDeviceInfoA returned wrong value: " ++ "expected 0 < x < (UINT)-1, got %u\n", ret); ++ size = strlen(buffer); ++ ok(size > 5, "GetRawInputDeviceInfoA returned too short device name: " ++ "expected x > 5, got %u\n", size); ++ ++ size = 0; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICEINFO, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoA returned wrong value: expected 0, got %u\n", ret); ++ ok(size == sizeof(RID_DEVICE_INFO), "GetRawInputDeviceInfoA returned " ++ "wrong device info size: expected sizeof(RID_DEVICE_INFO), got %u\n", size); ++ ++ size = sizeof(RID_DEVICE_INFO); ++ info.cbSize = sizeof(RID_DEVICE_INFO); ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_DEVICEINFO, &info, &size); ++ ok(ret == sizeof(RID_DEVICE_INFO), "GetRawInputDeviceInfoA returned wrong value: " ++ "expected sizeof(RID_DEVICE_INFO), got %u\n", ret); ++ ++ size = 0xdeadbeef; ++ ret = pGetRawInputDeviceInfoA(devices[0].hDevice, RIDI_PREPARSEDDATA, NULL, &size); ++ ok(ret == 0, "GetRawInputDeviceInfoA returned wrong value: " ++ "expected 0, got %u\n", ret); ++ ok(size == 0, "GetRawInputDeviceInfoA returned wrong preparsed data size: " ++ "expected 0, got %u\n", size); ++ ++ HeapFree(GetProcessHeap(), 0, devices); ++} ++ ++static void test_basic_get_registered_raw_input_devices(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; ++ } ++ ++ /* Basic tests for GetRegisteredRawInputDevices */ ++ SetLastError(0xdeadbeef); ++ ret2 = pGetRegisteredRawInputDevices(NULL, NULL, 0); ++ error = GetLastError(); ++ ok(ret2 == (UINT)-1, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret2); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret2 = pGetRegisteredRawInputDevices(NULL, NULL, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(ret2 == (UINT)-1, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret2); ++ ok(error == ERROR_NOACCESS, "GetRegisteredRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, 1); ++ error = GetLastError(); ++ ok(ret2 == (UINT)-1, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret2); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRegisteredRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ device.usUsagePage = HID_USAGE_PAGE_GENERIC; ++ device.usUsage = HID_USAGE_GENERIC_MOUSE; ++ device.dwFlags = 0; ++ device.hwndTarget = NULL; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to subscribe to mouse raw input\n"); ++ ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 1, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 1, got %u\n", count); ++ ++ memset(&devices[0], 0xFF, sizeof(RAWINPUTDEVICE)); ++ ret2 = pGetRegisteredRawInputDevices(&devices[0], &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 1, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 1, got %u\n", ret2); ++ ok(memcmp(&device, &devices[0], sizeof(RAWINPUTDEVICE)) == 0, ++ "GetRegisteredRawInputDevices returned incorrect raw input device registration\n"); ++ ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to resubscribe to mouse raw input\n"); ++ ++ /* Verify that there is still the only one registration */ ++ memset(&devices[0], 0xFF, sizeof(RAWINPUTDEVICE)); ++ ret2 = pGetRegisteredRawInputDevices(&devices[0], &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 1, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 1, got %u\n", ret2); ++ ok(memcmp(&device, &devices[0], sizeof(RAWINPUTDEVICE)) == 0, ++ "GetRegisteredRawInputDevices returned incorrect raw input device registration\n"); ++ ++ device.dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe from mouse raw input\n"); ++ ++ /* Verify that no registrations are present */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++} ++ ++static void test_basic_register_raw_input_devices(void) ++{ ++ RAWINPUTDEVICE device; ++ BOOL ret; ++ UINT ret2, count; ++ DWORD error; ++ ++ if (!pGetRegisteredRawInputDevices || !pRegisterRawInputDevices) ++ { ++ win_skip("GetRegisteredRawInputDevices and RegisterRawInputDevices are not available\n"); ++ return; ++ } ++ ++ /* Basic tests for RegisterRawInputDevices */ ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(NULL, 0, 0); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(NULL, 0, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ device.usUsagePage = HID_USAGE_PAGE_GENERIC; ++ device.usUsage = HID_USAGE_GENERIC_MOUSE; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to subscribe to mouse raw input\n"); ++ ++ device.dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe from mouse raw input\n"); ++ ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to reunsubscribe from mouse raw input\n"); ++ ++ device.usUsagePage = 0xFF; ++ device.usUsage = 0xFF; ++ device.dwFlags = 0; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to subscribe to a non-existing device\n"); ++ ++ device.dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe from a non-existing device\n"); ++ ++ /* Assert that no registrations are present */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++} ++ ++static void test_raw_input_device_flag_preconditions(void) ++{ ++ RAWINPUTDEVICE device; ++ BOOL ret; ++ UINT ret2, count; ++ DWORD error; ++ ++ if (!pGetRegisteredRawInputDevices || !pRegisterRawInputDevices) ++ { ++ win_skip("GetRegisteredRawInputDevices and RegisterRawInputDevices are not available\n"); ++ return; ++ } ++ ++ /* Test that RIDEV_REMOVE flags requires hwndTarget to be null*/ ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_PAGEONLY requires usUsage to be 0 */ ++ device.usUsage = 0xFF; ++ device.dwFlags = RIDEV_PAGEONLY; ++ device.hwndTarget = NULL; ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_EXCLUDE requires usUsage to be non-0 */ ++ device.usUsage = 0; ++ device.dwFlags = RIDEV_EXCLUDE; ++ device.hwndTarget = NULL; ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_NOLEGACY cannot be used with other device then mouse and keyboard */ ++ device.usUsage = 0xFF; ++ device.dwFlags = RIDEV_NOLEGACY; ++ device.hwndTarget = NULL; ++ SetLastError(0xdeadbeef); ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ error = GetLastError(); ++ ok(!ret, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_INPUTSINK requires hwndTarget to be non-null */ ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_CAPTUREMOUSE must be combined with RIDEV_NOLEGACY ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_FLAGS, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_APPKEYS must be combined with RIDEV_NOLEGACY */ ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_FLAGS, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_APPKEYS cannot be used with mouse */ ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_FLAGS, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test that RIDEV_NOHOTKEYS cannot be used with mouse */ ++ 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_FLAGS, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* 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, "RegisterRawInputDevices should have failed\n"); ++ ok(error == ERROR_INVALID_FLAGS, "RegisterRawInputDevices returned " ++ "wrong error code: %u\n", error); ++ ++ /* Assert that no registrations are present */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++} ++ ++static void test_extended_register_raw_input_devices(void) ++{ ++ RAWINPUTDEVICE device, devices[2]; ++ BOOL ret; ++ UINT ret2, count; ++ ++ if (!pGetRegisteredRawInputDevices || !pRegisterRawInputDevices) ++ { ++ win_skip("GetRegisteredRawInputDevices and RegisterRawInputDevices are not available\n"); ++ return; ++ } ++ ++ /* 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, "RegisterRawInputDevices failed to subscribe to a usage page\n"); ++ ++ device.dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe to a usage page\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ /* 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, "RegisterRawInputDevices failed to exclude mouse raw input\n"); ++ ok(ret, "Given (&device{1,2,RIDEV_EXCLUDE,0}, 1, sizeof), " ++ "RegisterRawInputDevices should successfully exclude a device from input feed\n"); ++ ++ /* Assert that there is one registration */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 1, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 1, got %u\n", count); ++ ++ device.dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&device, 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe\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, "RegisterRawInputDevices failed to exclude and include mouse raw input " ++ "in the same call\n"); ++ ++ devices[1].dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&devices[1], 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ /* 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, "RegisterRawInputDevices failed to subscribe\n"); ++ ++ devices[0].dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY; ++ ret = pRegisterRawInputDevices(&devices[0], 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe\n"); ++ ++ /* Assert that one device is registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 1, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 1, got %u\n", count); ++ ++ devices[1].dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(&devices[1], 1, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ /* 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, "RegisterRawInputDevices failed to subscribe\n"); ++ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 2, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 2, got %u\n", count); ++ ++ devices[0].dwFlags = RIDEV_REMOVE | RIDEV_PAGEONLY; ++ devices[1].dwFlags = RIDEV_REMOVE; ++ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE)); ++ ok(ret, "RegisterRawInputDevices failed to unsubscribe\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ /* 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, "RegisterRawInputDevices failed to subscribe and unsubscribe in the same call\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ /* Test that RegisterRawInputDevices is atomic, ++ if one device fails to register, no changes are made */ ++ 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 = 0; ++ devices[1].usUsage = 0; ++ devices[1].dwFlags = 0; ++ devices[1].hwndTarget = NULL; ++ ret = pRegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE)); ++ ok(!ret, "RegisterRawInputDevices should fail to register the devices\n"); ++ ++ /* Assert that there are no devices registered */ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++} ++ ++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, "GetRawInputData returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputData returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pGetRawInputData(NULL, 0, NULL, NULL, sizeof(RAWINPUTHEADER)); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputData returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_HANDLE, "GetRawInputData returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pGetRawInputData(NULL, 0, NULL, &count, 1); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputData returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputData returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pGetRawInputData(NULL, 0, NULL, &count, sizeof(RAWINPUTHEADER)); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputData returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_HANDLE, "GetRawInputData returned " ++ "wrong error code: %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, "GetRawInputBuffer returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pGetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER)); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputBuffer returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned " ++ "wrong error code: %u\n", error); ++ ++ SetLastError(0xdeadbeef); ++ ret = pGetRawInputBuffer(NULL, &size, 1); ++ error = GetLastError(); ++ ok(ret == (UINT)-1, "GetRawInputBuffer returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned " ++ "wrong error code: %u\n", error); ++ ++ size = 0xdeadbeef; ++ ret = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret == 0, "GetRawInputBuffer returned wrong value: expected 0, got %u\n", ret); ++ ok(size == 0, "GetRawInputBuffer returned wrong minimal buffer size: " ++ "expected 0, got %u\n", size); ++} ++ ++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, "GetRawInputData returned wrong value: " ++ "expected (UINT)-1, got %u\n", ret); ++ ok(error == ERROR_NOACCESS, "GetRawInputData returned " ++ "wrong error code: %u\n", error); ++ ++ /* Test retrieving of RAWINPUT data */ ++ ret2 = pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, ++ sizeof(RAWINPUTHEADER)); ++ ok(ret2 == 0, "GetRawInputData 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, "GetRawInputData failed to retrieve raw input data\n"); ++ ok(raw->header.dwType == RIM_TYPEMOUSE || raw->header.dwType == RIM_TYPEKEYBOARD, ++ "Raw input data entry was not from mouse or keyboard, expected otherwise\n"); ++ ++ ret3 = pDefRawInputProc(&raw, 1, sizeof(RAWINPUTHEADER)); ++ ok(ret3 == S_OK, "DefRawInputProc failed\n"); ++ ++ ret2 = pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw, &dwSize, ++ sizeof(RAWINPUTHEADER)); ++ ok(ret2 == dwSize, "GetRawInputData failed to reretrieve raw input data after " ++ "calling DefRawInputProc\n"); ++ ++ 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; ++ UINT ret2, size, ret3, i; ++ RAWINPUT *raw, *raw2; ++ ++ 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); ++ ++ /* Flush queued messages */ ++ while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) ++ { ++ TranslateMessage(&msg); ++ DispatchMessageA(&msg); ++ } ++ ++ 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, "RegisterRawInputDevices failed to subscribe to " ++ "a raw input device: %u\n", GetLastError()); ++ ++ ok(!GetInputState(), "GetInputState returned that there are mouse or keyboard " ++ "messages queued, expected otherwise\n"); ++ size = 0xdeadbeef; ++ ret2 = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret2 == 0, "GetRawInputBuffer returned wrong value: expected 0, got %u\n", ret2); ++ ok(size == 0, "GetRawInputBuffer returned incorrect minimum buffer size: " ++ "expected 0, got %u\n", size); ++ ++ /* First send input to test raw input buffer */ ++ pSendInput(input_count, input, sizeof(INPUT)); ++ ++ ok(GetQueueStatus(QS_RAWINPUT), "GetQueueStatus returned that the queue was " ++ "not marked as containing raw input messages, expected otherwise\n"); ++ size = 0; ++ ret2 = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret2 == 0, "GetRawInputBuffer returned wrong value: expected 0, got %u\n", ret2); ++ ok(size > 0, "GetRawInputBuffer returned incorrect minimum buffer size: " ++ "expected x > 0, got %u\n", size); ++ ++ /* Size variable is the size of a single entry of what GetRawInputBuffer will return, ++ therefore we will allocate enough space to accommodate 16 entries */ ++ size *= 16; ++ raw = HeapAlloc(GetProcessHeap(), 0, size * sizeof(RAWINPUT)); ++ ok(raw != NULL, "HeapAlloc failed to allocate memory for raw input buffer data\n"); ++ if (raw) ++ { ++ ret3 = pGetRawInputBuffer(raw, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret3 > 0 && ret3 != (UINT)-1, "GetRawInputBuffer failed to read raw input buffer\n"); ++ for (i = 0, raw2 = raw; ret3 != (UINT)-1 && i < ret3; i++) ++ { ++ ok(raw2->header.dwType == RIM_TYPEMOUSE || raw2->header.dwType == RIM_TYPEKEYBOARD, ++ "Raw input event was not from mouse or keyboard, expected otherwise\n"); ++ ok( ++ (raw2->header.dwType == RIM_TYPEMOUSE && ++ raw2->header.dwSize == sizeof(RAWINPUTHEADER) + sizeof(RAWMOUSE)) || ++ (raw2->header.dwType == RIM_TYPEKEYBOARD && ++ raw2->header.dwSize == sizeof(RAWINPUTHEADER) + sizeof(RAWKEYBOARD)), ++ "Raw input event size didn't match the one expected for mouse or keyboard\n"); ++ raw2 = NEXTRAWINPUTBLOCK(raw2); ++ } ++ HeapFree(GetProcessHeap(), 0, raw); ++ } ++ ret2 = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret2 == 0, "GetRawInputBuffer returned wrong value: expected 0, got %u\n", ret2); ++ ok(size == 0, "GetRawInputBuffer returned incorrect minimum buffer size: " ++ "expected 0, got %u\n", size); ++ ++ /* Proceed with testing other functionality */ ++ pSendInput(input_count, input, sizeof(INPUT)); ++ ++ ok(GetQueueStatus(QS_RAWINPUT), "GetQueueStatus returned that the queue was " ++ "not marked as containing raw input messages, expected otherwise\n"); ++ ret2 = pGetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER)); ++ ok(ret2 == 0, "GetRawInputBuffer returned wrong value: expected 0, got %u\n", ret2); ++ ok(size > 0, "GetRawInputBuffer returned incorrect minimum buffer size: " ++ "expected x > 0, got %u\n", size); ++ ++ /* 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"); ++ ok(!GetQueueStatus(QS_RAWINPUT), "GetQueueStatus returned that the queue was " ++ "marked as containing raw input messages, expected otherwise\n"); ++ ++ return hWnd; ++} ++ ++static void test_get_raw_input_data_simulation_teardown(HWND hWnd, RAWINPUTDEVICE *device) ++{ ++ BOOL ret; ++ UINT ret2; ++ DWORD count; ++ ++ 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, "RegisterRawInputDevices failed to unsubscribe from " ++ "a raw input device: %u\n", GetLastError()); ++ ++ count = 0xdeadbeef; ++ ret2 = pGetRegisteredRawInputDevices(NULL, &count, sizeof(RAWINPUTDEVICE)); ++ ok(ret2 == 0, "GetRegisteredRawInputDevices returned wrong value: " ++ "expected 0, got %u\n", ret2); ++ ok(count == 0, "GetRegisteredRawInputDevices returned incorrect registration count: " ++ "expected 0, got %u\n", count); ++ ++ DestroyWindow(hWnd); ++} ++ ++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, ++ "Didn't receive legacy mouse messages, while was expecting to\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, ++ "Didn't receive keyboard messages, while was expecting to\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, ++ "Didn't receive legacy mouse messages, while was expecting to\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, ++ "Didn't receive legacy keyboard messages, while was expecting to\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, ++ "Did receive legacy mouse messages, while was expecting not to\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, ++ "Did receive legacy mouse messages, while was expecting not to\n"); ++ test_get_raw_input_data_simulation_teardown(hWnd, &device); ++} ++ + START_TEST(input) + { + init_function_pointers(); +@@ -1617,6 +2800,18 @@ 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_basic_get_registered_raw_input_devices(); ++ test_basic_register_raw_input_devices(); ++ test_raw_input_device_flag_preconditions(); ++ test_extended_register_raw_input_devices(); ++ test_get_raw_input_data(); ++ test_get_raw_input_buffer(); ++ test_get_raw_input_data_simulation(); ++ + if(pGetMouseMovePointsEx) + test_GetMouseMovePointsEx(); + else +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..6b5e348 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; +@@ -419,6 +424,7 @@ static void process_destroy( struct object *obj ) + + close_process_handles( process ); + set_process_startup_state( process, STARTUP_ABORTED ); ++ release_raw_input( &process->raw_registered, &process->raw_inputs ); + if (process->console) release_object( process->console ); + if (process->parent) release_object( process->parent ); + if (process->msg_fd) release_object( process->msg_fd ); +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..51f5d0d 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3365,3 +3365,74 @@ 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 ++ ++/* 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 the 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 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 ++ ++/* Register raw input devices */ ++@REQ(register_raw_input_devices) ++ unsigned int count; /* number of registrations submitted */ ++ VARARG(registrations,bytes); /* raw_input_device_registration structures (see below) */ ++@END ++struct raw_input_device_registration ++{ ++ 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 */ ++}; ++#define RAW_INPUT_DEVICE_FLAG_REMOVE 0x0001 ++#define RAW_INPUT_DEVICE_FLAG_PAGEONLY 0x0002 ++#define RAW_INPUT_DEVICE_FLAG_EXCLUDE 0x0004 ++#define RAW_INPUT_DEVICE_FLAG_NOLEGACY 0x0008 ++#define RAW_INPUT_DEVICE_FLAG_NOHOTKEYS 0x0010 ++#define RAW_INPUT_DEVICE_FLAG_CAPTUREMOUSE 0x0020 ++#define RAW_INPUT_DEVICE_FLAG_APPKEYS 0x0040 ++#define RAW_INPUT_DEVICE_FLAG_INPUTSINK 0x0080 ++#define RAW_INPUT_DEVICE_FLAG_EXINPUTSINK 0x0100 ++#define RAW_INPUT_DEVICE_FLAG_DEVNOTIFY 0x0200 ++ ++/* 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 the required size to store the data */ ++ unsigned int header_size; /* client size of RAWINPUTHEADER data structure */ ++@REPLY ++ data_size_t size; /* size of the raw input data */ ++ VARARG(data,bytes); /* RAWINPUTHEADER or RAWINPUT data structure */ ++@END ++ ++/* Get buffered raw input data */ ++@REQ(get_raw_input_buffer) ++ unsigned int report_size_only; /* reply only with the minimum size to get the first entry */ ++ unsigned int header_size; /* client size of RAWINPUTHEADER data structure */ ++@REPLY ++ unsigned int count; /* count of raw input events returned */ ++ data_size_t minimum_size; /* minimum buffer size to retrieve a buffered entry */ ++ VARARG(data,bytes); /* RAWINPUT data structures */ ++@END +diff --git a/server/queue.c b/server/queue.c +index 3fa546e..e0843e0 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)) +@@ -121,6 +122,7 @@ struct msg_queue + unsigned int changed_mask; /* changed wakeup mask */ + int paint_count; /* pending paint messages count */ + int hotkey_count; /* pending hotkey messages count */ ++ int rawinput_count; /* pending raw input messages count */ + int quit_message; /* is there a pending quit message? */ + int exit_code; /* exit code of pending quit message */ + int cursor_count; /* per-queue cursor show count */ +@@ -281,6 +283,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->changed_mask = 0; + queue->paint_count = 0; + queue->hotkey_count = 0; ++ queue->rawinput_count = 0; + queue->quit_message = 0; + queue->cursor_count = 0; + queue->recv_result = NULL; +@@ -437,6 +440,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 ) + { +@@ -604,6 +613,8 @@ static void remove_queue_message( struct msg_queue *queue, struct message *msg, + clear_queue_bits( queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); + if (msg->msg == WM_HOTKEY && --queue->hotkey_count == 0) + clear_queue_bits( queue, QS_HOTKEY ); ++ if (msg->msg == WM_INPUT && --queue->rawinput_count == 0) ++ clear_queue_bits( queue, QS_RAWINPUT ); + break; + } + free_message( msg ); +@@ -1455,7 +1466,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 */ +@@ -1960,6 +1974,11 @@ void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lpa + set_queue_bits( thread->queue, QS_HOTKEY ); + thread->queue->hotkey_count++; + } ++ if (message == WM_INPUT) ++ { ++ set_queue_bits( thread->queue, QS_RAWINPUT ); ++ thread->queue->rawinput_count++; ++ } + } + release_object( thread ); + } +@@ -2022,6 +2041,52 @@ void free_hotkeys( struct desktop *desktop, user_handle_t window ) + } + + ++/* Get the count and handles of queued raw input messages */ ++BOOL get_queued_raw_input_message_handles( lparam_t **handles, unsigned int *count ) ++{ ++ struct msg_queue *queue = get_current_queue(); ++ struct message *msg; ++ unsigned int index = 0; ++ ++ if (!queue->rawinput_count) ++ { ++ *handles = NULL; ++ *count = 0; ++ return TRUE; ++ } ++ ++ *handles = mem_alloc( queue->rawinput_count * sizeof( lparam_t ) ); ++ if (!*handles) ++ return FALSE; ++ ++ *count = queue->rawinput_count; ++ ++ LIST_FOR_EACH_ENTRY( msg, &queue->msg_list[POST_MESSAGE], struct message, entry ) ++ { ++ if (msg->msg == WM_INPUT) ++ (*handles)[index++] = msg->lparam; ++ } ++ ++ return TRUE; ++} ++ ++/* Remove given amount of raw input messages */ ++void dequeue_raw_input_messages( unsigned int count ) ++{ ++ struct msg_queue *queue = get_current_queue(); ++ struct message *msg, *msg2; ++ ++ LIST_FOR_EACH_ENTRY_SAFE( msg, msg2, &queue->msg_list[POST_MESSAGE], struct message, entry ) ++ { ++ if (msg->msg != WM_INPUT) ++ continue; ++ if (!count--) ++ break; ++ remove_queue_message( queue, msg, POST_MESSAGE ); ++ } ++} ++ ++ + /* check if the thread owning the window is hung */ + DECL_HANDLER(is_window_hung) + { +@@ -2203,9 +2268,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..6c7b245 +--- /dev/null ++++ b/server/raw_input.c +@@ -0,0 +1,747 @@ ++/* ++ * 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 ++#include ++#include ++ ++#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" ++ ++#define MAX_RAW_INPUT_QUEUE_LENGTH 32 ++ ++#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) ++ ++extern BOOL get_queued_raw_input_message_handles( lparam_t **handles, unsigned int *count ); ++extern void dequeue_raw_input_messages( unsigned int count ); ++ ++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; ++}; ++ ++/* Data structures to supply data for 32bit client from a 64bit server */ ++struct RAWINPUTHEADER32 ++{ ++ DWORD dwType; ++ DWORD dwSize; ++ DWORD hDevice; ++ DWORD wParam; ++}; ++ ++struct RAWINPUT32 ++{ ++ struct RAWINPUTHEADER32 header; ++ union ++ { ++ RAWMOUSE mouse; ++ RAWKEYBOARD keyboard; ++ } data; ++}; ++ ++/* Raw input device names */ ++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] )) ++ ++/* Release allocated raw input data */ ++void release_raw_input( struct list *registrations, struct list *inputs ) ++{ ++ struct raw_registration *registration, *registration2; ++ struct raw_input *input, *input2; ++ ++ LIST_FOR_EACH_ENTRY_SAFE( registration, registration2, registrations, ++ struct raw_registration, entry ) ++ { ++ list_remove( ®istration->entry ); ++ free( registration ); ++ } ++ ++ LIST_FOR_EACH_ENTRY_SAFE( input, input2, inputs, struct raw_input, entry ) ++ { ++ list_remove( &input->entry ); ++ free( input ); ++ } ++} ++ ++/* Register or unregister a given raw input device registration */ ++static void register_raw_input_device( struct raw_input_device_registration *new_registration ) ++{ ++ struct raw_registration *registration; ++ LIST_FOR_EACH_ENTRY( registration, ¤t->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 != new_registration->usage_page || ++ (!(registration->flags & RAW_INPUT_DEVICE_FLAG_PAGEONLY && ++ new_registration->flags & RAW_INPUT_DEVICE_FLAG_PAGEONLY) && ++ (registration->flags & RAW_INPUT_DEVICE_FLAG_PAGEONLY || ++ new_registration->flags & RAW_INPUT_DEVICE_FLAG_PAGEONLY || ++ registration->usage != new_registration->usage))) ++ continue; ++ ++ if (new_registration->flags & RAW_INPUT_DEVICE_FLAG_REMOVE) ++ { ++ list_remove( ®istration->entry ); ++ free( registration ); ++ return; ++ } ++ ++ /* Update existing registration */ ++ registration->flags = new_registration->flags; ++ registration->target_window = new_registration->target_window; ++ return; ++ } ++ ++ if (new_registration->flags & RAW_INPUT_DEVICE_FLAG_REMOVE || ++ !(registration = mem_alloc( sizeof( *registration ) ))) ++ return; ++ ++ registration->usage_page = new_registration->usage_page; ++ registration->usage = new_registration->usage; ++ registration->flags = new_registration->flags; ++ registration->target_window = new_registration->target_window; ++ ++ list_add_tail( ¤t->process->raw_registered, ®istration->entry ); ++} ++ ++/* 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( ¤t->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, ¤t->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( ¤t->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 queued raw input event by its handle id */ ++static struct raw_input *find_raw_input_event( unsigned int handle ) ++{ ++ struct raw_input *input; ++ LIST_FOR_EACH_ENTRY( input, ¤t->process->raw_inputs, struct raw_input, entry ) ++ { ++ if (input->handle == handle) ++ return input; ++ } ++ return NULL; ++} ++ ++/* 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, ¤t->process->raw_registered, ++ struct raw_registration, entry ) ++ { ++ if (registration->usage_page != usage_page) ++ continue; ++ else if (registration->flags & RAW_INPUT_DEVICE_FLAG_EXCLUDE && ++ registration->usage == usage) ++ return NULL; ++ else if (registration->flags & RAW_INPUT_DEVICE_FLAG_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( RAWINPUTHEADER ) + sizeof( RAWMOUSE ); ++ input->raw.header.hDevice = (HANDLE)(ULONG_PTR)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( RAWINPUTHEADER ) + sizeof( RAWKEYBOARD ); ++ input->raw.header.hDevice = (HANDLE)(ULONG_PTR)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 & RAW_INPUT_DEVICE_FLAG_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 & RAW_INPUT_DEVICE_FLAG_NOLEGACY : FALSE; ++} ++ ++static UINT apply_32bit_header_size(UINT size) ++{ ++ return size - sizeof( RAWINPUTHEADER ) + sizeof( struct RAWINPUTHEADER32 ); ++} ++ ++static void copy_32bit_raw_input_data(void *target, RAWINPUT *source, UINT size) ++{ ++ struct RAWINPUT32 *ptr32bit = (struct RAWINPUT32 *)target; ++ ptr32bit->header.dwType = source->header.dwType; ++ ptr32bit->header.dwSize = size; ++ ptr32bit->header.hDevice = (DWORD)(ULONG_PTR)source->header.hDevice; ++ ptr32bit->header.wParam = (DWORD)(ULONG_PTR)source->header.wParam; ++ memcpy( &ptr32bit->data, &source->data, size - sizeof( struct RAWINPUTHEADER32 ) ); ++} ++ ++/* 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)(ULONG_PTR)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(¤t->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, ¤t->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)(ULONG_PTR)registration->target_window; ++ index += 1; ++ } ++} ++ ++/* Register raw input devices */ ++DECL_HANDLER(register_raw_input_devices) ++{ ++ struct raw_input_device_registration *registrations = ++ (struct raw_input_device_registration *)get_req_data(); ++ unsigned int i; ++ for (i = 0; i < req->count; i++) ++ register_raw_input_device( ®istrations[i] ); ++} ++ ++/* Get raw input data */ ++DECL_HANDLER(get_raw_input_data) ++{ ++ void *ptr; ++ struct raw_input *input = find_raw_input_event( req->handle ); ++ const unsigned int is_server64bit = sizeof( RAWINPUTHEADER ) != sizeof( struct RAWINPUTHEADER32 ); ++ const unsigned int is_client32bit = req->header_size == sizeof( struct RAWINPUTHEADER32 ); ++ const unsigned int is_64bit_to_32bit = is_server64bit && is_client32bit; ++ ++ if (!input) ++ { ++ set_error( STATUS_INVALID_HANDLE ); ++ return; ++ } ++ ++ if (req->command == RID_HEADER && is_64bit_to_32bit) ++ reply->size = sizeof( struct RAWINPUTHEADER32 ); ++ else if (req->command == RID_HEADER) ++ reply->size = sizeof( RAWINPUTHEADER ); ++ else if (req->command == RID_INPUT && is_64bit_to_32bit) ++ reply->size = apply_32bit_header_size( input->raw.header.dwSize ); ++ else if (req->command == RID_INPUT) ++ reply->size = input->raw.header.dwSize; ++ 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; ++ } ++ ++ if (is_64bit_to_32bit) ++ copy_32bit_raw_input_data( ptr, &input->raw, reply->size ); ++ else ++ memcpy( ptr, &input->raw, reply->size ); ++ ++ if (req->command == RID_INPUT) ++ input->retrieved = TRUE; ++} ++ ++/* Get buffered raw input data */ ++DECL_HANDLER(get_raw_input_buffer) ++{ ++ unsigned int i, count, written_count = 0, written_size = 0; ++ lparam_t *handles; ++ RAWINPUT *result = NULL; ++ UINT tmp_size; ++ const unsigned int is_server64bit = sizeof( RAWINPUTHEADER ) != sizeof( struct RAWINPUTHEADER32 ); ++ const unsigned int is_client32bit = req->header_size == sizeof( struct RAWINPUTHEADER32 ); ++ const unsigned int is_64bit_to_32bit = is_server64bit && is_client32bit; ++ ++ reply->count = 0; ++ reply->minimum_size = 0; ++ ++ if (!get_queued_raw_input_message_handles( &handles, &count )) ++ { ++ set_error( STATUS_NO_MEMORY ); ++ return; ++ } ++ if (!count) ++ return; ++ ++ if (!req->report_size_only) ++ { ++ result = set_reply_data_size( get_reply_max_size() ); ++ if (!result) ++ { ++ free( handles ); ++ set_error( STATUS_NO_MEMORY ); ++ return; ++ } ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ struct raw_input *input = find_raw_input_event( handles[i] ); ++ ++ if (!input) ++ continue; ++ ++ if (is_64bit_to_32bit) ++ tmp_size = apply_32bit_header_size( input->raw.header.dwSize ); ++ else ++ tmp_size = input->raw.header.dwSize; ++ ++ if (!reply->minimum_size) ++ reply->minimum_size = tmp_size; ++ ++ if (written_size + tmp_size > get_reply_max_size() || req->report_size_only) ++ break; ++ ++ if (is_64bit_to_32bit) ++ copy_32bit_raw_input_data( result, &input->raw, tmp_size ); ++ else ++ memcpy( result, &input->raw, tmp_size ); ++ ++ written_count += 1; ++ written_size += tmp_size; ++ result = NEXTRAWINPUTBLOCK( result ); ++ ++ remove_raw_input( input ); ++ } ++ ++ free( handles ); ++ ++ if (req->report_size_only) ++ return; ++ ++ /* Windows needs the buffer to be at least 1 byte larger then ++ the minimum needed space */ ++ if (reply->minimum_size >= get_reply_max_size() || !written_count) ++ { ++ set_error( STATUS_BUFFER_TOO_SMALL ); ++ return; ++ } ++ ++ reply->count = written_count; ++ ++ dequeue_raw_input_messages( written_count ); ++} +diff --git a/server/raw_input.h b/server/raw_input.h +new file mode 100644 +index 0000000..4a4acf0 +--- /dev/null ++++ b/server/raw_input.h +@@ -0,0 +1,38 @@ ++/* ++ * 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 ++ */ ++ ++#ifndef __WINE_SERVER_RAW_INPUT_H ++#define __WINE_SERVER_RAW_INPUT_H ++ ++#include "wine/server_protocol.h" ++#include "wine/list.h" ++ ++extern void release_raw_input( struct list *registrations, struct list *inputs ); ++ ++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/wine-rawinput/wine.install b/wine-rawinput/wine.install new file mode 100644 index 0000000..33b351d --- /dev/null +++ b/wine-rawinput/wine.install @@ -0,0 +1,57 @@ +post_upgrade() { + update-desktop-database -q + echo "This wine package is wow64 enabled. This means it can run 32bit/64bit Windows apps on x86_64." + echo "If you are on x86_64, the default WINEARCH will be win64." + echo "This will cause a lot of Windows applications to malfunction even if they usually work in wine." + echo "Please create your ~/.wine with 'WINEARCH=win32 winecfg' if you are unsure and on x86_64." + echo "See the Arch wiki on wine for more information." + echo "" + echo "" + echo "KDE 4 Menu Fix" + echo "The Wine menu items may appear in 'Lost & Found' instead of the Wine menu for KDE 4." + echo "This is because kde-applications.menu is missing the MergeDir option." + echo "Edit /etc/xdg/menus/kde-applications.menu" + echo "At the end of the file add applications-merged after , " + echo "it should look like this:" + echo " " + echo " " + echo " KDE" + echo " Core" + echo " " + echo " " + echo " " + echo " applications-merged " + echo " applications-kmenuedit.menu" + echo "" +} + +post_install() { + update-desktop-database -q + echo "This wine package is wow64 enabled. This means it can run 32bit/64bit Windows apps on x86_64." + echo "If you are on x86_64, the default WINEARCH will be win64." + echo "This will cause a lot of Windows applications to malfunction even if they usually work in wine." + echo "Please create your ~/.wine with 'WINEARCH=win32 winecfg' if you are unsure and on x86_64." + echo "See the Arch wiki on wine for more information." + echo "" + echo "" + echo "KDE 4 Menu Fix" + echo "The Wine menu items may appear in 'Lost & Found' instead of the Wine menu for KDE 4." + echo "This is because kde-applications.menu is missing the MergeDir option." + echo "Edit /etc/xdg/menus/kde-applications.menu" + echo "At the end of the file add applications-merged after , " + echo "it should look like this:" + echo " " + echo " " + echo " KDE" + echo " Core" + echo " " + echo " " + echo " " + echo " applications-merged " + echo " applications-kmenuedit.menu" + echo "" +} + +post_remove() { + update-desktop-database -q +} \ No newline at end of file