4 * Copyright 1993 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <X11/Xatom.h>
25 #include <X11/keysym.h>
27 #include <X11/Xresource.h>
28 #include <X11/Xutil.h>
34 #define NONAMELESSUNION
35 #define NONAMELESSSTRUCT
40 #include "shlobj.h" /* DROPFILES */
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(event);
50 extern BOOL ximInComposeMode;
52 #define DndNotDnd -1 /* OffiX drag&drop */
64 #define DndURL 128 /* KDE drag&drop */
67 static void EVENT_FocusIn( HWND hwnd, XEvent *event );
68 static void EVENT_FocusOut( HWND hwnd, XEvent *event );
69 static void EVENT_PropertyNotify( HWND hwnd, XEvent *event );
70 static void EVENT_ClientMessage( HWND hwnd, XEvent *event );
74 int type; /* event type */
75 x11drv_event_handler handler; /* corresponding handler function */
78 #define MAX_EVENT_HANDLERS 64
80 static struct event_handler handlers[MAX_EVENT_HANDLERS] =
82 /* list must be sorted by event type */
83 { KeyPress, X11DRV_KeyEvent },
84 { KeyRelease, X11DRV_KeyEvent },
85 { ButtonPress, X11DRV_ButtonPress },
86 { ButtonRelease, X11DRV_ButtonRelease },
87 { MotionNotify, X11DRV_MotionNotify },
88 { EnterNotify, X11DRV_EnterNotify },
90 { FocusIn, EVENT_FocusIn },
91 { FocusOut, EVENT_FocusOut },
92 { KeymapNotify, X11DRV_KeymapNotify },
93 { Expose, X11DRV_Expose },
96 /* VisibilityNotify */
99 { UnmapNotify, X11DRV_UnmapNotify },
100 { MapNotify, X11DRV_MapNotify },
103 { ConfigureNotify, X11DRV_ConfigureNotify },
104 /* ConfigureRequest */
107 /* CirculateNotify */
108 /* CirculateRequest */
109 { PropertyNotify, EVENT_PropertyNotify },
110 { SelectionClear, X11DRV_SelectionClear },
111 { SelectionRequest, X11DRV_SelectionRequest },
112 /* SelectionNotify */
114 { ClientMessage, EVENT_ClientMessage },
115 { MappingNotify, X11DRV_MappingNotify },
118 static int nb_event_handlers = 18; /* change this if you add handlers above */
121 /* return the name of an X event */
122 static const char *dbgstr_event( int type )
124 static const char * const event_names[] =
126 "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
127 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
128 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
129 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
130 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
131 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
132 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
133 "ClientMessage", "MappingNotify"
136 if (type >= KeyPress && type <= MappingNotify) return event_names[type - KeyPress];
137 return wine_dbg_sprintf( "Extension event %d", type );
141 /***********************************************************************
144 * Find the handler for a given event type. Caller must hold the x11 lock.
146 static inline x11drv_event_handler find_handler( int type )
148 int min = 0, max = nb_event_handlers - 1;
152 int pos = (min + max) / 2;
153 if (handlers[pos].type == type) return handlers[pos].handler;
154 if (handlers[pos].type > type) max = pos - 1;
161 /***********************************************************************
162 * X11DRV_register_event_handler
164 * Register a handler for a given event type.
165 * If already registered, overwrite the previous handler.
167 void X11DRV_register_event_handler( int type, x11drv_event_handler handler )
173 max = nb_event_handlers - 1;
176 int pos = (min + max) / 2;
177 if (handlers[pos].type == type)
179 handlers[pos].handler = handler;
182 if (handlers[pos].type > type) max = pos - 1;
185 /* insert it between max and min */
186 memmove( &handlers[min+1], &handlers[min], (nb_event_handlers - min) * sizeof(handlers[0]) );
187 handlers[min].type = type;
188 handlers[min].handler = handler;
190 assert( nb_event_handlers <= MAX_EVENT_HANDLERS );
193 TRACE("registered handler %p for event %d count %d\n", handler, type, nb_event_handlers );
197 /***********************************************************************
200 static Bool filter_event( Display *display, XEvent *event, char *arg )
202 ULONG_PTR mask = (ULONG_PTR)arg;
204 if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return 1;
212 return (mask & QS_KEY) != 0;
215 return (mask & QS_MOUSEBUTTON) != 0;
219 return (mask & QS_MOUSEMOVE) != 0;
221 return (mask & QS_PAINT) != 0;
226 case ConfigureNotify:
229 return (mask & QS_POSTMESSAGE) != 0;
231 return (mask & QS_SENDMESSAGE) != 0;
236 /***********************************************************************
239 static int process_events( Display *display, ULONG_PTR mask )
244 x11drv_event_handler handler;
247 while (XCheckIfEvent( display, &event, filter_event, (char *)mask ))
250 if (XFilterEvent( &event, None )) continue; /* filtered, ignore it */
252 if (!(handler = find_handler( event.type )))
254 TRACE( "%s, ignoring\n", dbgstr_event( event.type ));
255 continue; /* no handler, ignore it */
258 if (XFindContext( display, event.xany.window, winContext, (char **)&hwnd ) != 0)
259 hwnd = 0; /* not for a registered window */
260 if (!hwnd && event.xany.window == root_window) hwnd = GetDesktopWindow();
263 TRACE( "%s for hwnd/window %p/%lx\n",
264 dbgstr_event( event.type ), hwnd, event.xany.window );
265 handler( hwnd, &event );
268 XFlush( gdi_display );
270 if (count) TRACE( "processed %d events\n", count );
275 /***********************************************************************
276 * MsgWaitForMultipleObjectsEx (X11DRV.@)
278 DWORD X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
279 DWORD timeout, DWORD mask, DWORD flags )
282 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
286 if (!count && !timeout) return WAIT_TIMEOUT;
287 return WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
288 timeout, flags & MWMO_ALERTABLE );
291 if (data->process_event_count) mask = 0; /* don't process nested events */
293 data->process_event_count++;
295 if (process_events( data->display, mask )) ret = count - 1;
296 else if (count || timeout)
298 ret = WaitForMultipleObjectsEx( count, handles, flags & MWMO_WAITALL,
299 timeout, flags & MWMO_ALERTABLE );
300 if (ret == count - 1) process_events( data->display, mask );
302 else ret = WAIT_TIMEOUT;
304 data->process_event_count--;
308 /***********************************************************************
309 * EVENT_x11_time_to_win32_time
311 * Make our timer and the X timer line up as best we can
312 * Pass 0 to retrieve the current adjustment value (times -1)
314 DWORD EVENT_x11_time_to_win32_time(Time time)
316 static DWORD adjust = 0;
317 DWORD now = GetTickCount();
320 if (! adjust && time != 0)
327 /* If we got an event in the 'future', then our clock is clearly wrong.
328 If we got it more than 10000 ms in the future, then it's most likely
329 that the clock has wrapped. */
332 if (ret > now && ((ret - now) < 10000) && time != 0)
343 /*******************************************************************
344 * can_activate_window
346 * Check if we can activate the specified window.
348 static inline BOOL can_activate_window( HWND hwnd )
350 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
351 if (!(style & WS_VISIBLE)) return FALSE;
352 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
353 return !(style & WS_DISABLED);
357 /**********************************************************************
360 static void set_focus( HWND hwnd, Time time )
365 TRACE( "setting foreground window to %p\n", hwnd );
366 SetForegroundWindow( hwnd );
369 if (focus) focus = GetAncestor( focus, GA_ROOT );
370 win = X11DRV_get_whole_window(focus);
374 TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time );
376 XSetInputFocus( thread_display(), win, RevertToParent, time );
382 /**********************************************************************
383 * handle_wm_protocols
385 static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
387 Atom protocol = (Atom)event->data.l[0];
389 if (!protocol) return;
391 if (protocol == x11drv_atom(WM_DELETE_WINDOW))
393 /* Ignore the delete window request if the window has been disabled
394 * and we are in managed mode. This is to disallow applications from
395 * being closed by the window manager while in a modal state.
397 if (IsWindowEnabled(hwnd))
401 if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return;
402 hSysMenu = GetSystemMenu(hwnd, FALSE);
405 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
406 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
409 PostMessageW( hwnd, WM_X11DRV_DELETE_WINDOW, 0, 0 );
412 else if (protocol == x11drv_atom(WM_TAKE_FOCUS))
414 Time event_time = (Time)event->data.l[1];
415 HWND last_focus = x11drv_thread_data()->last_focus;
417 TRACE( "got take focus msg for %p, enabled=%d, visible=%d (style %08x), focus=%p, active=%p, fg=%p, last=%p\n",
418 hwnd, IsWindowEnabled(hwnd), IsWindowVisible(hwnd), GetWindowLongW(hwnd, GWL_STYLE),
419 GetFocus(), GetActiveWindow(), GetForegroundWindow(), last_focus );
421 if (can_activate_window(hwnd))
423 /* simulate a mouse click on the caption to find out
424 * whether the window wants to be activated */
425 LRESULT ma = SendMessageW( hwnd, WM_MOUSEACTIVATE,
426 (WPARAM)GetAncestor( hwnd, GA_ROOT ),
427 MAKELONG(HTCAPTION,WM_LBUTTONDOWN) );
428 if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) set_focus( hwnd, event_time );
429 else TRACE( "not setting focus to %p (%lx), ma=%ld\n", hwnd, event->window, ma );
434 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
435 if (!hwnd) hwnd = GetActiveWindow();
436 if (!hwnd) hwnd = last_focus;
437 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, event_time );
440 else if (protocol == x11drv_atom(_NET_WM_PING))
442 XClientMessageEvent xev;
445 TRACE("NET_WM Ping\n");
447 xev.window = DefaultRootWindow(xev.display);
448 XSendEvent(xev.display, xev.window, False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*)&xev);
450 /* this line is semi-stolen from gtk2 */
451 TRACE("NET_WM Pong\n");
456 static const char * const focus_details[] =
462 "NotifyNonlinearVirtual",
468 /**********************************************************************
471 static void EVENT_FocusIn( HWND hwnd, XEvent *xev )
473 XFocusChangeEvent *event = &xev->xfocus;
478 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
480 if (event->detail == NotifyPointer) return;
482 if ((xic = X11DRV_get_ic( hwnd )))
488 if (use_take_focus) return; /* ignore FocusIn if we are using take focus */
490 if (!can_activate_window(hwnd))
492 HWND hwnd = GetFocus();
493 if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT );
494 if (!hwnd) hwnd = GetActiveWindow();
495 if (!hwnd) hwnd = x11drv_thread_data()->last_focus;
496 if (hwnd && can_activate_window(hwnd)) set_focus( hwnd, CurrentTime );
498 else SetForegroundWindow( hwnd );
502 /**********************************************************************
505 * Note: only top-level windows get FocusOut events.
507 static void EVENT_FocusOut( HWND hwnd, XEvent *xev )
509 XFocusChangeEvent *event = &xev->xfocus;
517 TRACE( "win %p xwin %lx detail=%s\n", hwnd, event->window, focus_details[event->detail] );
519 if (event->detail == NotifyPointer) return;
520 if (ximInComposeMode) return;
522 x11drv_thread_data()->last_focus = hwnd;
523 if ((xic = X11DRV_get_ic( hwnd )))
526 XUnsetICFocus( xic );
529 if (hwnd != GetForegroundWindow()) return;
530 SendMessageW( hwnd, WM_CANCELMODE, 0, 0 );
532 /* don't reset the foreground window, if the window which is
533 getting the focus is a Wine window */
536 XGetInputFocus( thread_display(), &focus_win, &revert );
539 if (XFindContext( thread_display(), focus_win, winContext, (char **)&hwnd_tmp ) != 0)
546 /* Abey : 6-Oct-99. Check again if the focus out window is the
547 Foreground window, because in most cases the messages sent
548 above must have already changed the foreground window, in which
549 case we don't have to change the foreground window to 0 */
550 if (hwnd == GetForegroundWindow())
552 TRACE( "lost focus, setting fg to 0\n" );
553 SetForegroundWindow( 0 );
559 /***********************************************************************
560 * EVENT_PropertyNotify
561 * We use this to release resources like Pixmaps when a selection
562 * client no longer needs them.
564 static void EVENT_PropertyNotify( HWND hwnd, XEvent *xev )
566 XPropertyEvent *event = &xev->xproperty;
567 /* Check if we have any resources to free */
568 TRACE("Received PropertyNotify event:\n");
574 TRACE("\tPropertyDelete for atom %ld on window %ld\n",
575 event->atom, (long)event->window);
579 case PropertyNewValue:
581 TRACE("\tPropertyNewValue for atom %ld on window %ld\n\n",
582 event->atom, (long)event->window);
591 static HWND find_drop_window( HWND hQueryWnd, LPPOINT lpPt )
595 if (!IsWindowEnabled(hQueryWnd)) return 0;
597 GetWindowRect(hQueryWnd, &tempRect);
599 if(!PtInRect(&tempRect, *lpPt)) return 0;
601 if (!IsIconic( hQueryWnd ))
604 ScreenToClient( hQueryWnd, &pt );
605 GetClientRect( hQueryWnd, &tempRect );
607 if (PtInRect( &tempRect, pt))
609 HWND ret = ChildWindowFromPointEx( hQueryWnd, pt, CWP_SKIPINVISIBLE|CWP_SKIPDISABLED );
610 if (ret && ret != hQueryWnd)
612 ret = find_drop_window( ret, lpPt );
618 if(!(GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return 0;
620 ScreenToClient(hQueryWnd, lpPt);
625 /**********************************************************************
626 * EVENT_DropFromOffix
628 * don't know if it still works (last Changlog is from 96/11/04)
630 static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event )
632 unsigned long data_length;
633 unsigned long aux_long;
634 unsigned char* p_data = NULL;
638 Window win, w_aux_root, w_aux_child;
642 win = X11DRV_get_whole_window(hWnd);
644 XQueryPointer( event->display, win, &w_aux_root, &w_aux_child,
645 &x, &y, &dummy, &dummy, (unsigned int*)&aux_long);
646 x += virtual_screen_rect.left;
647 y += virtual_screen_rect.top;
650 pWnd = WIN_GetPtr(hWnd);
652 /* find out drop point and drop window */
653 if( x < 0 || y < 0 ||
654 x > (pWnd->rectWindow.right - pWnd->rectWindow.left) ||
655 y > (pWnd->rectWindow.bottom - pWnd->rectWindow.top) )
657 bAccept = pWnd->dwExStyle & WS_EX_ACCEPTFILES;
664 HWND hwndDrop = find_drop_window( hWnd, &pt );
677 WIN_ReleasePtr(pWnd);
679 if (!bAccept) return;
682 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
683 x11drv_atom(DndSelection), 0, 65535, FALSE,
684 AnyPropertyType, &atom_aux, &dummy,
685 &data_length, &aux_long, &p_data);
688 if( !aux_long && p_data) /* don't bother if > 64K */
690 char *p = (char *)p_data;
694 while( *p ) /* calculate buffer size */
696 INT len = GetShortPathNameA( p, NULL, 0 );
697 if (len) aux_long += len + 1;
700 if( aux_long && aux_long < 65535 )
705 aux_long += sizeof(DROPFILES) + 1;
706 hDrop = GlobalAlloc( GMEM_SHARE, aux_long );
707 lpDrop = (DROPFILES*)GlobalLock( hDrop );
711 WND *pDropWnd = WIN_GetPtr( hScope );
712 lpDrop->pFiles = sizeof(DROPFILES);
716 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
717 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
718 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
719 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
720 lpDrop->fWide = FALSE;
721 WIN_ReleasePtr(pDropWnd);
722 p_drop = (char *)(lpDrop + 1);
726 if (GetShortPathNameA( p, p_drop, aux_long - (p_drop - (char *)lpDrop) ))
727 p_drop += strlen( p_drop ) + 1;
731 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
736 if( p_data ) XFree(p_data);
740 /**********************************************************************
743 * drop items are separated by \n
744 * each item is prefixed by its mime type
746 * event->data.l[3], event->data.l[4] contains drop x,y position
748 static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event )
750 unsigned long data_length;
751 unsigned long aux_long, drop_len = 0;
752 unsigned char *p_data = NULL; /* property data */
765 if (!(GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES)) return;
768 XGetWindowProperty( event->display, DefaultRootWindow(event->display),
769 x11drv_atom(DndSelection), 0, 65535, FALSE,
770 AnyPropertyType, &u.atom_aux, &u.i,
771 &data_length, &aux_long, &p_data);
774 WARN("property too large, truncated!\n");
775 TRACE("urls=%s\n", p_data);
777 if( !aux_long && p_data) { /* don't bother if > 64K */
778 /* calculate length */
780 next = strchr(p, '\n');
783 if (strncmp(p,"file:",5) == 0 ) {
784 INT len = GetShortPathNameA( p+5, NULL, 0 );
785 if (len) drop_len += len + 1;
790 next = strchr(p, '\n');
796 if( drop_len && drop_len < 65535 ) {
798 XQueryPointer( event->display, root_window, &u.w_aux, &u.w_aux,
799 &x, &y, &u.i, &u.i, &u.u);
800 x += virtual_screen_rect.left;
801 y += virtual_screen_rect.top;
804 drop_len += sizeof(DROPFILES) + 1;
805 hDrop = GlobalAlloc( GMEM_SHARE, drop_len );
806 lpDrop = (DROPFILES *) GlobalLock( hDrop );
809 WND *pDropWnd = WIN_GetPtr( hWnd );
810 lpDrop->pFiles = sizeof(DROPFILES);
811 lpDrop->pt.x = (INT)x;
812 lpDrop->pt.y = (INT)y;
814 ( x < (pDropWnd->rectClient.left - pDropWnd->rectWindow.left) ||
815 y < (pDropWnd->rectClient.top - pDropWnd->rectWindow.top) ||
816 x > (pDropWnd->rectClient.right - pDropWnd->rectWindow.left) ||
817 y > (pDropWnd->rectClient.bottom - pDropWnd->rectWindow.top) );
818 lpDrop->fWide = FALSE;
819 p_drop = (char*)(lpDrop + 1);
820 WIN_ReleasePtr(pDropWnd);
823 /* create message content */
826 next = strchr(p, '\n');
829 if (strncmp(p,"file:",5) == 0 ) {
830 INT len = GetShortPathNameA( p+5, p_drop, 65535 );
832 TRACE("drop file %s as %s\n", p+5, p_drop);
835 WARN("can't convert file %s to dos name\n", p+5);
838 WARN("unknown mime type %s\n", p);
843 next = strchr(p, '\n');
851 PostMessageA( hWnd, WM_DROPFILES, (WPARAM)hDrop, 0L );
855 if( p_data ) XFree(p_data);
860 /**********************************************************************
861 * handle_dnd_protocol
863 static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event )
866 int root_x, root_y, child_x, child_y;
869 /* query window (drag&drop event contains only drag window) */
871 XQueryPointer( event->display, root_window, &root, &child,
872 &root_x, &root_y, &child_x, &child_y, &u);
873 if (XFindContext( event->display, child, winContext, (char **)&hwnd ) != 0) hwnd = 0;
876 if (event->data.l[0] == DndFile || event->data.l[0] == DndFiles)
877 EVENT_DropFromOffiX(hwnd, event);
878 else if (event->data.l[0] == DndURL)
879 EVENT_DropURLs(hwnd, event);
883 struct client_message_handler
885 int atom; /* protocol atom */
886 void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */
889 static const struct client_message_handler client_messages[] =
891 { XATOM_WM_PROTOCOLS, handle_wm_protocols },
892 { XATOM_DndProtocol, handle_dnd_protocol },
893 { XATOM_XdndEnter, X11DRV_XDND_EnterEvent },
894 { XATOM_XdndPosition, X11DRV_XDND_PositionEvent },
895 { XATOM_XdndDrop, X11DRV_XDND_DropEvent },
896 { XATOM_XdndLeave, X11DRV_XDND_LeaveEvent }
900 /**********************************************************************
901 * EVENT_ClientMessage
903 static void EVENT_ClientMessage( HWND hwnd, XEvent *xev )
905 XClientMessageEvent *event = &xev->xclient;
910 if (event->format != 32)
912 WARN( "Don't know how to handle format %d\n", event->format );
916 for (i = 0; i < sizeof(client_messages)/sizeof(client_messages[0]); i++)
918 if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM])
920 client_messages[i].handler( hwnd, event );
924 TRACE( "no handler found for %ld\n", event->message_type );
928 /**********************************************************************
929 * X11DRV_WindowMessage (X11DRV.@)
931 LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
935 case WM_X11DRV_ACQUIRE_SELECTION:
936 return X11DRV_AcquireClipboard( hwnd );
937 case WM_X11DRV_DELETE_WINDOW:
938 return SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
940 FIXME( "got window msg %x hwnd %p wp %x lp %lx\n", msg, hwnd, wp, lp );
946 /***********************************************************************
947 * X11DRV_SendInput (X11DRV.@)
949 UINT X11DRV_SendInput( UINT count, LPINPUT inputs, int size )
953 for (i = 0; i < count; i++, inputs++)
958 X11DRV_send_mouse_input( 0, inputs->u.mi.dwFlags, inputs->u.mi.dx, inputs->u.mi.dy,
959 inputs->u.mi.mouseData, inputs->u.mi.time,
960 inputs->u.mi.dwExtraInfo, LLMHF_INJECTED );
963 X11DRV_send_keyboard_input( inputs->u.ki.wVk, inputs->u.ki.wScan, inputs->u.ki.dwFlags,
964 inputs->u.ki.time, inputs->u.ki.dwExtraInfo, LLKHF_INJECTED );
967 FIXME( "INPUT_HARDWARE not supported\n" );