From: "Vincas Miliūnas" Subject: [PATCH 2/3] server: Added server-side raw input function implementations (try 6) Message-Id: <4E016F0D.7000600@gmail.com> Date: Wed, 22 Jun 2011 07:26:53 +0300 (see the message in the first part of the patch) --- server/Makefile.in | 1 + server/process.c | 6 + server/process.h | 5 + server/protocol.def | 51 +++++ server/queue.c | 9 + server/raw_input.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++++ server/raw_input.h | 35 +++ 7 files changed, 686 insertions(+), 0 deletions(-) create mode 100644 server/raw_input.c create mode 100644 server/raw_input.h diff --git a/server/Makefile.in b/server/Makefile.in index a2f1a52..c12b2df 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -28,6 +28,7 @@ C_SRCS = \ procfs.c \ ptrace.c \ queue.c \ + raw_input.c \ region.c \ registry.c \ request.c \ diff --git a/server/process.c b/server/process.c index c88c89b..7d0b2ca 100644 --- a/server/process.c +++ b/server/process.c @@ -333,10 +333,16 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit process->desktop = 0; process->token = NULL; process->trace_data = 0; + process->raw_inputs_head = 0; + process->raw_inputs_tail = 0; list_init( &process->thread_list ); list_init( &process->locks ); list_init( &process->classes ); list_init( &process->dlls ); + list_init( &process->raw_registered ); + process->raw_inputs = mem_alloc( MAX_RAW_INPUT_QUEUE_LENGTH * sizeof(struct raw_input*) ); + if (!process->raw_inputs) + goto error; process->start_time = current_time; process->end_time = 0; diff --git a/server/process.h b/server/process.h index da51a0e..85dd116 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 raw_input **raw_inputs; /* queued raw inputs */ + unsigned int raw_inputs_head; /* head position of raw inputs queue */ + unsigned int raw_inputs_tail; /* tail position of raw inputs queue */ }; struct process_snapshot diff --git a/server/protocol.def b/server/protocol.def index 123f16a..d15c1fb 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3365,3 +3365,54 @@ 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 + unsigned int num_devices; + VARARG(devices,bytes); +@END + +/* Register a raw input device */ +@REQ(register_raw_input_device) + unsigned short usage_page; + unsigned short usage; + unsigned int flags; + user_handle_t target_window; +@END + +/* Unregister a raw input device */ +@REQ(unregister_raw_input_device) + unsigned short usage_page; + unsigned short usage; +@END + +/* Get raw input data */ +@REQ(get_raw_input_data) + user_handle_t handle; + unsigned int command; + unsigned int report_size_only; +@REPLY + data_size_t size; + VARARG(data,bytes); +@END + +/* Get the registered raw input devices */ +@REQ(get_registered_raw_input_devices) + unsigned int report_size_only; +@REPLY + unsigned int num_devices; + VARARG(devices,bytes); +@END + +/* Get the raw input device info */ +@REQ(get_raw_input_device_info) + user_handle_t handle; + unsigned int command; + unsigned int report_size_only; +@REPLY + data_size_t size; + VARARG(info,bytes); +@END diff --git a/server/queue.c b/server/queue.c index 6dee8f5..512248b 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)) @@ -1586,6 +1587,10 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data->info = input->mouse.info; if (hook_flags & SEND_HWMSG_INJECTED) msg_data->flags = LLMHF_INJECTED; + queue_mouse_raw_input( msg->msg, msg_data->flags, msg->wparam, + input->mouse.info, msg_data->x, msg_data->y, desktop->cursor.x, + desktop->cursor.y, desktop->foreground_input ? desktop->foreground_input->focus : 0 ); + /* specify a sender only when sending the last message */ if (!(flags & ((1 << sizeof(messages)/sizeof(messages[0])) - 1))) { @@ -1703,6 +1708,10 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c desktop->keystate[VK_MENU] &= ~0x02; break; } + + queue_keyboard_raw_input( msg->msg, msg_data->flags, input->kbd.info, input->kbd.vkey, + input->kbd.scan, desktop->foreground_input ? desktop->foreground_input->focus : 0 ); + if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) queue_hardware_message( desktop, msg, 1 ); diff --git a/server/raw_input.c b/server/raw_input.c new file mode 100644 index 0000000..4ba41cb --- /dev/null +++ b/server/raw_input.c @@ -0,0 +1,579 @@ +/* + * 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 +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winnt.h" +#include "winternl.h" +#include "winbase.h" +#include "winuser.h" + +#include "request.h" +#include "process.h" +#include "user.h" +#include "raw_input.h" + +#define MOUSE_DEVICE_HANDLE 0x01 +#define KEYBOARD_DEVICE_HANDLE 0x02 + +#define MOUSE_USAGE_PAGE 0x01 +#define MOUSE_USAGE_ID 0x02 +#define KEYBOARD_USAGE_PAGE 0x01 +#define KEYBOARD_USAGE_ID 0x06 + +struct raw_registration +{ + struct list entry; + unsigned short usage_page; + unsigned short usage; + unsigned int flags; + user_handle_t target_window; +}; + +struct raw_input +{ + unsigned short usage_page; + unsigned short usage; + BOOL processed; + BOOL retrieved; + RAWINPUT raw; + + /* common fields */ + unsigned int type; + unsigned int message; + unsigned int flags; + unsigned int extra_info; + + union + { + struct + { + /* mouse fields */ + unsigned int point_x; + unsigned int point_y; + unsigned int mouse_data; + unsigned int cursor_x; + unsigned int cursor_y; + }; + + struct + { + /* keyboard fields */ + unsigned int vk_code; + unsigned int scan_code; + }; + }; +}; + +struct raw_device +{ + user_handle_t handle; + unsigned short usage_page; + unsigned short usage; + const WCHAR *name; + RID_DEVICE_INFO info; +}; + +static const WCHAR mouse_raw_input_device_name[] = + {'W','I','N','E',' ','R','a','w',' ','I','n','p','u','t',' ','M','o','u','s','e',0}; +static const WCHAR keyboard_raw_input_device_name[] = + {'W','I','N','E',' ','R','a','w',' ','I','n','p','u','t',' ','K','e','y','b','o','a','r','d',0}; + +/* standard raw input devices with typical device info values */ +static const struct raw_device raw_devices[] = +{ + {MOUSE_DEVICE_HANDLE, MOUSE_USAGE_PAGE, MOUSE_USAGE_ID, mouse_raw_input_device_name, + {sizeof( RID_DEVICE_INFO ), RIM_TYPEMOUSE, {mouse: {1, 3, 100, FALSE}}}}, + {KEYBOARD_DEVICE_HANDLE, KEYBOARD_USAGE_PAGE, KEYBOARD_USAGE_ID, keyboard_raw_input_device_name, + {sizeof( RID_DEVICE_INFO ), RIM_TYPEKEYBOARD, {keyboard: {4, 0, 1, 12, 3, 101}}}} +}; +#define NUM_RAW_DEVICES (sizeof( raw_devices ) / sizeof( raw_devices[0] )) + +/* Get the raw input device list */ +DECL_HANDLER(get_raw_input_device_list) +{ + unsigned int i, size_in_bytes; + RAWINPUTDEVICELIST *result; + + reply->num_devices = NUM_RAW_DEVICES; + if (!reply->num_devices || req->report_size_only) + return; + + size_in_bytes = reply->num_devices * sizeof( RAWINPUTDEVICELIST ); + if (size_in_bytes > get_reply_max_size()) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + result = set_reply_data_size( size_in_bytes ); + if (!result) + { + set_error( STATUS_NO_MEMORY ); + return; + } + + for (i = 0; i < reply->num_devices; i++) + { + /* Currently fake handles are provided, however they are only used to identify the devices + for the GetRawInputDeviceInfo function, thus it should not create any undesirable side effects */ + result[i].hDevice = (HANDLE)raw_devices[i].handle; + result[i].dwType = raw_devices[i].info.dwType; + } +} + +/* Register a raw input device */ +DECL_HANDLER(register_raw_input_device) +{ + struct raw_registration *registration; + LIST_FOR_EACH_ENTRY( registration, ¤t->process->raw_registered, struct raw_registration, entry ) + { + if (registration->usage_page == req->usage_page && registration->usage == req->usage) + { + /* Update existing registration */ + registration->flags = req->flags; + registration->target_window = req->target_window; + return; + } + } + + if (!(registration = mem_alloc( sizeof( *registration ) ))) + return; + + registration->usage_page = req->usage_page; + registration->usage = req->usage; + registration->flags = req->flags; + registration->target_window = req->target_window; + + list_add_tail( ¤t->process->raw_registered, ®istration->entry ); +} + +/* Unregister a raw input device */ +DECL_HANDLER(unregister_raw_input_device) +{ + struct raw_registration *registration; + LIST_FOR_EACH_ENTRY( registration, ¤t->process->raw_registered, struct raw_registration, entry ) + { + if (registration->usage_page == req->usage_page && registration->usage == req->usage) + { + list_remove( ®istration->entry ); + free( registration ); + break; + } + } +} + +/* Determine mouse flags */ +static unsigned int map_mouse_flags(unsigned int message, unsigned int mouse_data) +{ + const int tmp = HIWORD(mouse_data); + switch(message) + { + case WM_LBUTTONDOWN: + return RI_MOUSE_LEFT_BUTTON_DOWN; + case WM_LBUTTONUP: + return RI_MOUSE_LEFT_BUTTON_UP; + case WM_RBUTTONDOWN: + return RI_MOUSE_RIGHT_BUTTON_DOWN; + case WM_RBUTTONUP: + return RI_MOUSE_RIGHT_BUTTON_UP; + case WM_MBUTTONDOWN: + return RI_MOUSE_MIDDLE_BUTTON_DOWN; + case WM_MBUTTONUP: + return RI_MOUSE_MIDDLE_BUTTON_UP; + case WM_MOUSEWHEEL: + return RI_MOUSE_WHEEL; + case WM_XBUTTONDOWN: + switch(tmp) + { + case XBUTTON1: + return RI_MOUSE_BUTTON_4_DOWN; + case XBUTTON2: + return RI_MOUSE_BUTTON_5_DOWN; + default: + return 0; + } + case WM_XBUTTONUP: + switch(tmp) + { + case XBUTTON1: + return RI_MOUSE_BUTTON_4_UP; + case XBUTTON2: + return RI_MOUSE_BUTTON_5_UP; + default: + return 0; + } + default: + return 0; + } +} + +/* Determine keyboard flags */ +static int map_keyboard_flags(unsigned int flags, unsigned int vk_code) +{ + unsigned int result = 0; + if (flags & LLKHF_UP) + result |= RI_KEY_BREAK; + else + result |= RI_KEY_MAKE; + /* the left/right RI_KEY_E0/RI_KEY_E1 flags are not directly provided, but can be inferred */ + return result; +} + +/* setup the windows raw input structure */ +static void map_raw_input(struct raw_input *raw) +{ + RAWINPUT *result = &raw->raw; + + result->header.dwType = raw->type; + result->header.dwSize = sizeof( RAWINPUT ); + result->header.wParam = RIM_INPUT; + + if (raw->type == RIM_TYPEMOUSE) + { + result->header.hDevice = (HANDLE)MOUSE_DEVICE_HANDLE; + + result->data.mouse.usFlags = MOUSE_MOVE_RELATIVE; + result->data.mouse.usButtonFlags = map_mouse_flags( raw->message, raw->mouse_data ); + if (result->data.mouse.usButtonFlags & (RI_MOUSE_WHEEL | RI_MOUSE_HORIZONTAL_WHEEL)) + result->data.mouse.usButtonData = HIWORD( raw->mouse_data ); + else + result->data.mouse.usButtonData = 0; + /* ulRawButtons is undocumented and hardware/drivers dependent, therefore 0 is a valid value */ + result->data.mouse.ulRawButtons = 0; + result->data.mouse.lLastX = raw->point_x - raw->cursor_x; + result->data.mouse.lLastY = raw->point_y - raw->cursor_y; + result->data.mouse.ulExtraInformation = raw->extra_info; + } + else if (raw->type == RIM_TYPEKEYBOARD) + { + result->header.hDevice = (HANDLE)KEYBOARD_DEVICE_HANDLE; + + result->data.keyboard.MakeCode = raw->scan_code; + result->data.keyboard.Flags = map_keyboard_flags( raw->flags, raw->vk_code ); + result->data.keyboard.Reserved = 0; + result->data.keyboard.VKey = raw->vk_code; + result->data.keyboard.Message = raw->message; + result->data.keyboard.ExtraInformation = raw->extra_info; + } +} + +/* Get raw input data */ +DECL_HANDLER(get_raw_input_data) +{ + struct raw_input *raw; + void *ptr; + const unsigned int raw_index = req->handle; + const unsigned int tmp = raw_index % MAX_RAW_INPUT_QUEUE_LENGTH; + + BOOL valid = FALSE; + /* when not overflowed */ + valid |= current->process->raw_inputs_head >= current->process->raw_inputs_tail && + raw_index >= current->process->raw_inputs_tail && raw_index < current->process->raw_inputs_head; + /* when overflowed */ + valid |= current->process->raw_inputs_head < current->process->raw_inputs_tail && + (raw_index >= current->process->raw_inputs_tail || raw_index < current->process->raw_inputs_head); + if (valid) + valid &= current->process->raw_inputs[tmp] != NULL; + + if (!valid) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + + if (req->command == RID_HEADER) + { + reply->size = sizeof( RAWINPUTHEADER ); + } + else if (req->command == RID_INPUT) + { + reply->size = sizeof( RAWINPUT ); + } + else + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + if (req->report_size_only) + return; + + if (reply->size > get_reply_max_size()) + { + set_error( STATUS_BUFFER_TOO_SMALL ); + return; + } + + raw = current->process->raw_inputs[tmp]; + + if (!raw->processed) + { + map_raw_input( raw ); + raw->processed = TRUE; + } + + ptr = set_reply_data_size( reply->size ); + if (!ptr) + { + set_error( STATUS_NO_MEMORY ); + return; + } + + memcpy( ptr, &raw->raw, reply->size ); + + if (req->command == RID_INPUT) + raw->retrieved = TRUE; +} + +/* Get the registered raw input devices */ +DECL_HANDLER(get_registered_raw_input_devices) +{ + unsigned int i = 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[i].usUsagePage = registration->usage_page; + result[i].usUsage = registration->usage; + result[i].dwFlags = registration->flags; + result[i].hwndTarget = (HWND)registration->target_window; + i += 1; + } +} + +/* 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 ); + } +} + +/* find a raw input device registration */ +static struct raw_registration* find_raw_input_device_registration(unsigned int usage_page, unsigned int usage) +{ + struct raw_registration *registration; + LIST_FOR_EACH_ENTRY( registration, ¤t->process->raw_registered, struct raw_registration, entry ) + { + if (registration->usage_page == usage_page && registration->usage == usage) + return registration; + } + return NULL; +} + +/* queue a raw input event */ +static void queue_raw_input(struct raw_input *raw, struct raw_registration *registration, user_handle_t focus) +{ + user_handle_t target; + unsigned int i, head, tail, prev = 0; + BOOL prev_set = FALSE; + + const unsigned int raw_index = current->process->raw_inputs_head; + const unsigned int tmp1 = current->process->raw_inputs_head % MAX_RAW_INPUT_QUEUE_LENGTH; + current->process->raw_inputs[tmp1] = raw; + current->process->raw_inputs_head += 1; + + /* Prevent unprocessed raw input entries from being queued indefinitely */ + head = current->process->raw_inputs_head; + tail = current->process->raw_inputs_tail; + if (head != tail && (head - tail) % MAX_RAW_INPUT_QUEUE_LENGTH == 0) + { + const unsigned int tmp2 = current->process->raw_inputs_tail % MAX_RAW_INPUT_QUEUE_LENGTH; + if (current->process->raw_inputs[tmp2]) + free( current->process->raw_inputs[tmp2] ); + current->process->raw_inputs_tail += 1; + } + + /* Release raw input entries, that are retrieved and added before the current entry for this device */ + for (i = current->process->raw_inputs_tail; i != current->process->raw_inputs_head; i++) + { + const unsigned int tmp3 = i % MAX_RAW_INPUT_QUEUE_LENGTH; + struct raw_input *input = current->process->raw_inputs[tmp3]; + if (!input) + { + if (i == current->process->raw_inputs_tail) + current->process->raw_inputs_tail += 1; + continue; + } + + if (input->usage_page != registration->usage_page || input->usage != registration->usage) + continue; + + if (input->retrieved) + { + /* Delay releasing the entry to make sure that the last retrieved entry is still in the list, + because, while processing a WM_INPUT message, its contents can retrieved multiple times */ + if (prev_set) + { + const unsigned int tmp4 = prev % MAX_RAW_INPUT_QUEUE_LENGTH; + free( current->process->raw_inputs[tmp4] ); + if (prev == current->process->raw_inputs_tail) + { + /* if it's the last record, just move the tail */ + current->process->raw_inputs_tail += 1; + } + else + { + current->process->raw_inputs[tmp4] = NULL; + } + } + + prev = i; + prev_set = TRUE; + } + else + break; + } + + target = registration->target_window ? registration->target_window : focus; + if (target) + post_message( target, WM_INPUT, RIM_INPUT, raw_index ); +} + +/* queue a mouse raw input event */ +void queue_mouse_raw_input(unsigned int message, unsigned int flags, unsigned int data, unsigned int info, + unsigned int x, unsigned int y, unsigned int cursor_x, unsigned int cursor_y, user_handle_t focus) +{ + struct raw_input *raw; + struct raw_registration *registration = find_raw_input_device_registration( MOUSE_USAGE_PAGE, MOUSE_USAGE_ID ); + + if (!registration || !(raw = mem_alloc( sizeof( *raw ) ))) + return; + + raw->usage_page = MOUSE_USAGE_PAGE; + raw->usage = MOUSE_USAGE_ID; + raw->processed = FALSE; + raw->retrieved = FALSE; + + raw->type = RIM_TYPEMOUSE; + raw->message = message; + raw->flags = flags; + raw->extra_info = info; + + raw->point_x = x; + raw->point_y = y; + raw->mouse_data = data; + + raw->cursor_x = cursor_x; + raw->cursor_y = cursor_y; + + queue_raw_input( raw, registration, focus ); +} + +/* queue a keyboard raw input event */ +void queue_keyboard_raw_input(unsigned int message, unsigned int flags, unsigned int info, + unsigned int vk_code, unsigned int scan_code, user_handle_t focus) +{ + struct raw_input *raw; + struct raw_registration *registration = find_raw_input_device_registration( KEYBOARD_USAGE_PAGE, KEYBOARD_USAGE_ID ); + + if (!registration || !(raw = mem_alloc( sizeof( *raw ) ))) + return; + + raw->usage_page = KEYBOARD_USAGE_PAGE; + raw->usage = KEYBOARD_USAGE_ID; + raw->processed = FALSE; + raw->retrieved = FALSE; + + raw->type = RIM_TYPEKEYBOARD; + raw->message = message; + raw->flags = flags; + raw->extra_info = info; + + raw->vk_code = vk_code; + raw->scan_code = scan_code; + + queue_raw_input( raw, registration, focus ); +} diff --git a/server/raw_input.h b/server/raw_input.h new file mode 100644 index 0000000..63de53a --- /dev/null +++ b/server/raw_input.h @@ -0,0 +1,35 @@ +/* + * Server-side Raw Input Queuing Functions + * + * Copyright (C) 2011 Vincas Miliūnas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_SERVER_RAW_INPUT_H +#define __WINE_SERVER_RAW_INPUT_H + +#include "wine/server_protocol.h" + +#define MAX_RAW_INPUT_QUEUE_LENGTH 64 + +struct raw_input; + +extern void queue_mouse_raw_input(unsigned int message, unsigned int flags, unsigned int data, unsigned int info, + unsigned int x, unsigned int y, unsigned int cursor_x, unsigned int cursor_y, user_handle_t focus); +extern void queue_keyboard_raw_input(unsigned int message, unsigned int flags, unsigned int info, + unsigned int vk_code, unsigned int scan_code, user_handle_t focus); + +#endif /* __WINE_SERVER_RAW_INPUT_H */