d3d9/tests: Correct nv40 results.
[wine] / dlls / user32 / input.c
1 /*
2  * USER Input processing
3  *
4  * Copyright 1993 Bob Amstadt
5  * Copyright 1996 Albrecht Kleine
6  * Copyright 1997 David Faure
7  * Copyright 1998 Morten Welinder
8  * Copyright 1998 Ulrich Weigand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <ctype.h>
33 #include <assert.h>
34
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37 #include "ntstatus.h"
38 #define WIN32_NO_STATUS
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
43 #include "winnls.h"
44 #include "winternl.h"
45 #include "winerror.h"
46 #include "win.h"
47 #include "user_private.h"
48 #include "wine/server.h"
49 #include "wine/debug.h"
50 #include "wine/unicode.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(win);
53 WINE_DECLARE_DEBUG_CHANNEL(keyboard);
54
55
56 /***********************************************************************
57  *           get_key_state
58  */
59 static WORD get_key_state(void)
60 {
61     WORD ret = 0;
62
63     if (GetSystemMetrics( SM_SWAPBUTTON ))
64     {
65         if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
66         if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
67     }
68     else
69     {
70         if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
71         if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
72     }
73     if (GetAsyncKeyState(VK_MBUTTON) & 0x80)  ret |= MK_MBUTTON;
74     if (GetAsyncKeyState(VK_SHIFT) & 0x80)    ret |= MK_SHIFT;
75     if (GetAsyncKeyState(VK_CONTROL) & 0x80)  ret |= MK_CONTROL;
76     if (GetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
77     if (GetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
78     return ret;
79 }
80
81
82 /**********************************************************************
83  *              set_capture_window
84  */
85 BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
86 {
87     HWND previous = 0;
88     UINT flags = 0;
89     BOOL ret;
90
91     if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
92     if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;
93
94     SERVER_START_REQ( set_capture_window )
95     {
96         req->handle = wine_server_user_handle( hwnd );
97         req->flags  = flags;
98         if ((ret = !wine_server_call_err( req )))
99         {
100             previous = wine_server_ptr_handle( reply->previous );
101             hwnd = wine_server_ptr_handle( reply->full_handle );
102         }
103     }
104     SERVER_END_REQ;
105
106     if (ret)
107     {
108         USER_Driver->pSetCapture( hwnd, gui_flags );
109
110         if (previous && previous != hwnd)
111             SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
112
113         if (prev_ret) *prev_ret = previous;
114     }
115     return ret;
116 }
117
118
119 /***********************************************************************
120  *              __wine_send_input  (USER32.@)
121  *
122  * Internal SendInput function to allow the graphics driver to inject real events.
123  */
124 BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input )
125 {
126     NTSTATUS status = send_hardware_message( hwnd, input, 0 );
127     if (status) SetLastError( RtlNtStatusToDosError(status) );
128     return !status;
129 }
130
131
132 /***********************************************************************
133  *              update_mouse_coords
134  *
135  * Helper for SendInput.
136  */
137 static void update_mouse_coords( INPUT *input )
138 {
139     if (!(input->u.mi.dwFlags & MOUSEEVENTF_MOVE)) return;
140
141     if (input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE)
142     {
143         input->u.mi.dx = (input->u.mi.dx * GetSystemMetrics( SM_CXSCREEN )) >> 16;
144         input->u.mi.dy = (input->u.mi.dy * GetSystemMetrics( SM_CYSCREEN )) >> 16;
145     }
146     else
147     {
148         int accel[3];
149
150         /* dx and dy can be negative numbers for relative movements */
151         SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0);
152
153         if (!accel[2]) return;
154
155         if (abs(input->u.mi.dx) > accel[0])
156         {
157             input->u.mi.dx *= 2;
158             if ((abs(input->u.mi.dx) > accel[1]) && (accel[2] == 2)) input->u.mi.dx *= 2;
159         }
160         if (abs(input->u.mi.dy) > accel[0])
161         {
162             input->u.mi.dy *= 2;
163             if ((abs(input->u.mi.dy) > accel[1]) && (accel[2] == 2)) input->u.mi.dy *= 2;
164         }
165     }
166 }
167
168 /***********************************************************************
169  *              SendInput  (USER32.@)
170  */
171 UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
172 {
173     UINT i;
174     NTSTATUS status;
175
176     for (i = 0; i < count; i++)
177     {
178         if (inputs[i].type == INPUT_MOUSE)
179         {
180             /* we need to update the coordinates to what the server expects */
181             INPUT input = inputs[i];
182             update_mouse_coords( &input );
183             status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED );
184         }
185         else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED );
186
187         if (status)
188         {
189             SetLastError( RtlNtStatusToDosError(status) );
190             break;
191         }
192     }
193
194     return i;
195 }
196
197
198 /***********************************************************************
199  *              keybd_event (USER32.@)
200  */
201 void WINAPI keybd_event( BYTE bVk, BYTE bScan,
202                          DWORD dwFlags, ULONG_PTR dwExtraInfo )
203 {
204     INPUT input;
205
206     input.type = INPUT_KEYBOARD;
207     input.u.ki.wVk = bVk;
208     input.u.ki.wScan = bScan;
209     input.u.ki.dwFlags = dwFlags;
210     input.u.ki.time = 0;
211     input.u.ki.dwExtraInfo = dwExtraInfo;
212     SendInput( 1, &input, sizeof(input) );
213 }
214
215
216 /***********************************************************************
217  *              mouse_event (USER32.@)
218  */
219 void WINAPI mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
220                          DWORD dwData, ULONG_PTR dwExtraInfo )
221 {
222     INPUT input;
223
224     input.type = INPUT_MOUSE;
225     input.u.mi.dx = dx;
226     input.u.mi.dy = dy;
227     input.u.mi.mouseData = dwData;
228     input.u.mi.dwFlags = dwFlags;
229     input.u.mi.time = 0;
230     input.u.mi.dwExtraInfo = dwExtraInfo;
231     SendInput( 1, &input, sizeof(input) );
232 }
233
234
235 /***********************************************************************
236  *              GetCursorPos (USER32.@)
237  */
238 BOOL WINAPI DECLSPEC_HOTPATCH GetCursorPos( POINT *pt )
239 {
240     BOOL ret;
241     DWORD last_change;
242
243     if (!pt) return FALSE;
244
245     SERVER_START_REQ( set_cursor )
246     {
247         if ((ret = !wine_server_call( req )))
248         {
249             pt->x = reply->new_x;
250             pt->y = reply->new_y;
251             last_change = reply->last_change;
252         }
253     }
254     SERVER_END_REQ;
255
256     /* query new position from graphics driver if we haven't updated recently */
257     if (ret && GetTickCount() - last_change > 100) ret = USER_Driver->pGetCursorPos( pt );
258     return ret;
259 }
260
261
262 /***********************************************************************
263  *              GetCursorInfo (USER32.@)
264  */
265 BOOL WINAPI GetCursorInfo( PCURSORINFO pci )
266 {
267     BOOL ret;
268
269     if (!pci) return 0;
270
271     SERVER_START_REQ( get_thread_input )
272     {
273         req->tid = 0;
274         if ((ret = !wine_server_call( req )))
275         {
276             pci->hCursor = wine_server_ptr_handle( reply->cursor );
277             pci->flags = (reply->show_count >= 0) ? CURSOR_SHOWING : 0;
278         }
279     }
280     SERVER_END_REQ;
281     GetCursorPos(&pci->ptScreenPos);
282     return ret;
283 }
284
285
286 /***********************************************************************
287  *              SetCursorPos (USER32.@)
288  */
289 BOOL WINAPI DECLSPEC_HOTPATCH SetCursorPos( INT x, INT y )
290 {
291     BOOL ret;
292     INT prev_x, prev_y, new_x, new_y;
293
294     SERVER_START_REQ( set_cursor )
295     {
296         req->flags = SET_CURSOR_POS;
297         req->x     = x;
298         req->y     = y;
299         if ((ret = !wine_server_call( req )))
300         {
301             prev_x = reply->prev_x;
302             prev_y = reply->prev_y;
303             new_x  = reply->new_x;
304             new_y  = reply->new_y;
305         }
306     }
307     SERVER_END_REQ;
308     if (ret && (prev_x != new_x || prev_y != new_y)) USER_Driver->pSetCursorPos( new_x, new_y );
309     return ret;
310 }
311
312
313 /**********************************************************************
314  *              SetCapture (USER32.@)
315  */
316 HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
317 {
318     HWND previous = 0;
319
320     set_capture_window( hwnd, 0, &previous );
321     return previous;
322 }
323
324
325 /**********************************************************************
326  *              ReleaseCapture (USER32.@)
327  */
328 BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void)
329 {
330     BOOL ret = set_capture_window( 0, 0, NULL );
331
332     /* Somebody may have missed some mouse movements */
333     if (ret) mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
334
335     return ret;
336 }
337
338
339 /**********************************************************************
340  *              GetCapture (USER32.@)
341  */
342 HWND WINAPI GetCapture(void)
343 {
344     HWND ret = 0;
345
346     SERVER_START_REQ( get_thread_input )
347     {
348         req->tid = GetCurrentThreadId();
349         if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->capture );
350     }
351     SERVER_END_REQ;
352     return ret;
353 }
354
355
356 static void check_for_events( UINT flags )
357 {
358     if (USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, flags, 0 ) == WAIT_TIMEOUT)
359         flush_window_surfaces( TRUE );
360 }
361
362 /**********************************************************************
363  *              GetAsyncKeyState (USER32.@)
364  *
365  *      Determine if a key is or was pressed.  retval has high-order
366  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
367  * been pressed.
368  */
369 SHORT WINAPI DECLSPEC_HOTPATCH GetAsyncKeyState( INT key )
370 {
371     struct user_thread_info *thread_info = get_user_thread_info();
372     SHORT ret;
373
374     if (key < 0 || key >= 256) return 0;
375
376     check_for_events( QS_INPUT );
377
378     if ((ret = USER_Driver->pGetAsyncKeyState( key )) == -1)
379     {
380         if (thread_info->key_state &&
381             !(thread_info->key_state[key] & 0xc0) &&
382             GetTickCount() - thread_info->key_state_time < 50)
383             return 0;
384
385         if (!thread_info->key_state) thread_info->key_state = HeapAlloc( GetProcessHeap(), 0, 256 );
386
387         ret = 0;
388         SERVER_START_REQ( get_key_state )
389         {
390             req->tid = 0;
391             req->key = key;
392             if (thread_info->key_state) wine_server_set_reply( req, thread_info->key_state, 256 );
393             if (!wine_server_call( req ))
394             {
395                 if (reply->state & 0x40) ret |= 0x0001;
396                 if (reply->state & 0x80) ret |= 0x8000;
397                 thread_info->key_state_time = GetTickCount();
398             }
399         }
400         SERVER_END_REQ;
401     }
402     return ret;
403 }
404
405
406 /***********************************************************************
407  *              GetQueueStatus (USER32.@)
408  */
409 DWORD WINAPI GetQueueStatus( UINT flags )
410 {
411     DWORD ret;
412
413     if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
414     {
415         SetLastError( ERROR_INVALID_FLAGS );
416         return 0;
417     }
418
419     check_for_events( flags );
420
421     SERVER_START_REQ( get_queue_status )
422     {
423         req->clear = 1;
424         wine_server_call( req );
425         ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
426     }
427     SERVER_END_REQ;
428     return ret;
429 }
430
431
432 /***********************************************************************
433  *              GetInputState   (USER32.@)
434  */
435 BOOL WINAPI GetInputState(void)
436 {
437     DWORD ret;
438
439     check_for_events( QS_INPUT );
440
441     SERVER_START_REQ( get_queue_status )
442     {
443         req->clear = 0;
444         wine_server_call( req );
445         ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
446     }
447     SERVER_END_REQ;
448     return ret;
449 }
450
451
452 /******************************************************************
453  *              GetLastInputInfo (USER32.@)
454  */
455 BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii)
456 {
457     BOOL ret;
458
459     TRACE("%p\n", plii);
460
461     if (plii->cbSize != sizeof (*plii) )
462     {
463         SetLastError(ERROR_INVALID_PARAMETER);
464         return FALSE;
465     }
466
467     SERVER_START_REQ( get_last_input_time )
468     {
469         ret = !wine_server_call_err( req );
470         if (ret)
471             plii->dwTime = reply->time;
472     }
473     SERVER_END_REQ;
474     return ret;
475 }
476
477
478 /******************************************************************
479 *               GetRawInputDeviceList (USER32.@)
480 */
481 UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size)
482 {
483     TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size);
484
485     if (size != sizeof(*devices) || !device_count) return ~0U;
486
487     if (!devices)
488     {
489         *device_count = 2;
490         return 0;
491     }
492
493     if (*device_count < 2)
494     {
495         *device_count = 2;
496         return ~0U;
497     }
498
499     devices[0].hDevice = WINE_MOUSE_HANDLE;
500     devices[0].dwType = RIM_TYPEMOUSE;
501     devices[1].hDevice = WINE_KEYBOARD_HANDLE;
502     devices[1].dwType = RIM_TYPEKEYBOARD;
503
504     return 2;
505 }
506
507
508 /******************************************************************
509 *               RegisterRawInputDevices (USER32.@)
510 */
511 BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
512 {
513     struct rawinput_device *d;
514     BOOL ret;
515     UINT i;
516
517     TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
518
519     if (size != sizeof(*devices))
520     {
521         WARN("Invalid structure size %u.\n", size);
522         return FALSE;
523     }
524
525     if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;
526
527     for (i = 0; i < device_count; ++i)
528     {
529         TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
530                 i, devices[i].usUsagePage, devices[i].usUsage,
531                 devices[i].dwFlags, devices[i].hwndTarget);
532         if (devices[i].dwFlags & ~RIDEV_REMOVE)
533             FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
534
535         d[i].usage_page = devices[i].usUsagePage;
536         d[i].usage = devices[i].usUsage;
537         d[i].flags = devices[i].dwFlags;
538         d[i].target = wine_server_user_handle( devices[i].hwndTarget );
539     }
540
541     SERVER_START_REQ( update_rawinput_devices )
542     {
543         wine_server_add_data( req, d, device_count * sizeof(*d) );
544         ret = !wine_server_call( req );
545     }
546     SERVER_END_REQ;
547
548     HeapFree( GetProcessHeap(), 0, d );
549
550     return ret;
551 }
552
553
554 /******************************************************************
555 *               GetRawInputData (USER32.@)
556 */
557 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
558 {
559     RAWINPUT *ri = (RAWINPUT *)rawinput;
560     UINT s;
561
562     TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
563             rawinput, command, data, data_size, header_size);
564
565     if (header_size != sizeof(RAWINPUTHEADER))
566     {
567         WARN("Invalid structure size %u.\n", header_size);
568         return ~0U;
569     }
570
571     switch (command)
572     {
573     case RID_INPUT:
574         s = ri->header.dwSize;
575         break;
576     case RID_HEADER:
577         s = sizeof(RAWINPUTHEADER);
578         break;
579     default:
580         return ~0U;
581     }
582
583     if (!data)
584     {
585         *data_size = s;
586         return 0;
587     }
588
589     if (*data_size < s) return ~0U;
590     memcpy(data, ri, s);
591     return s;
592 }
593
594
595 /******************************************************************
596 *               GetRawInputBuffer (USER32.@)
597 */
598 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
599 {
600     FIXME("(pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n", pData, pcbSize, cbSizeHeader);
601
602     return 0;
603 }
604
605
606 /******************************************************************
607 *               GetRawInputDeviceInfoA (USER32.@)
608 */
609 UINT WINAPI GetRawInputDeviceInfoA(HANDLE device, UINT command, void *data, UINT *data_size)
610 {
611     UINT ret;
612
613     TRACE("device %p, command %u, data %p, data_size %p.\n", device, command, data, data_size);
614
615     ret = GetRawInputDeviceInfoW(device, command, data, data_size);
616     if (command == RIDI_DEVICENAME && ret && ret != ~0U)
617         ret = WideCharToMultiByte(CP_ACP, 0, data, -1, data, *data_size, NULL, NULL);
618
619     return ret;
620 }
621
622
623 /******************************************************************
624 *               GetRawInputDeviceInfoW (USER32.@)
625 */
626 UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT *data_size)
627 {
628     /* FIXME: Most of this is made up. */
629     static const WCHAR keyboard_name[] = {'\\','\\','?','\\','W','I','N','E','_','K','E','Y','B','O','A','R','D',0};
630     static const WCHAR mouse_name[] = {'\\','\\','?','\\','W','I','N','E','_','M','O','U','S','E',0};
631     static const RID_DEVICE_INFO_KEYBOARD keyboard_info = {0, 0, 1, 12, 3, 101};
632     static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE};
633     const WCHAR *name = NULL;
634     RID_DEVICE_INFO *info;
635     UINT s;
636
637     TRACE("device %p, command %u, data %p, data_size %p.\n", device, command, data, data_size);
638
639     if (!data_size || (device != WINE_MOUSE_HANDLE && device != WINE_KEYBOARD_HANDLE)) return ~0U;
640
641     switch (command)
642     {
643     case RIDI_DEVICENAME:
644         if (device == WINE_MOUSE_HANDLE)
645         {
646             s = sizeof(mouse_name);
647             name = mouse_name;
648         }
649         else
650         {
651             s = sizeof(keyboard_name);
652             name = keyboard_name;
653         }
654         break;
655     case RIDI_DEVICEINFO:
656         s = sizeof(*info);
657         break;
658     default:
659         return ~0U;
660     }
661
662     if (!data)
663     {
664         *data_size = s;
665         return 0;
666     }
667
668     if (*data_size < s)
669     {
670         *data_size = s;
671         return ~0U;
672     }
673
674     if (command == RIDI_DEVICENAME)
675     {
676         memcpy(data, name, s);
677         return s;
678     }
679
680     info = data;
681     info->cbSize = sizeof(*info);
682     if (device == WINE_MOUSE_HANDLE)
683     {
684         info->dwType = RIM_TYPEMOUSE;
685         info->u.mouse = mouse_info;
686     }
687     else
688     {
689         info->dwType = RIM_TYPEKEYBOARD;
690         info->u.keyboard = keyboard_info;
691     }
692     return s;
693 }
694
695
696 /******************************************************************
697 *               GetRegisteredRawInputDevices (USER32.@)
698 */
699 UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize)
700 {
701     FIXME("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDevices, puiNumDevices, cbSize);
702
703     return 0;
704 }
705
706
707 /******************************************************************
708 *               DefRawInputProc (USER32.@)
709 */
710 LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput, INT nInput, UINT cbSizeHeader)
711 {
712     FIXME("(paRawInput=%p, nInput=%d, cbSizeHeader=%d) stub!\n", *paRawInput, nInput, cbSizeHeader);
713
714     return 0;
715 }
716
717
718 /**********************************************************************
719  *              AttachThreadInput (USER32.@)
720  *
721  * Attaches the input processing mechanism of one thread to that of
722  * another thread.
723  */
724 BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
725 {
726     BOOL ret;
727
728     SERVER_START_REQ( attach_thread_input )
729     {
730         req->tid_from = from;
731         req->tid_to   = to;
732         req->attach   = attach;
733         ret = !wine_server_call_err( req );
734     }
735     SERVER_END_REQ;
736     return ret;
737 }
738
739
740 /**********************************************************************
741  *              GetKeyState (USER32.@)
742  *
743  * An application calls the GetKeyState function in response to a
744  * keyboard-input message.  This function retrieves the state of the key
745  * at the time the input message was generated.
746  */
747 SHORT WINAPI DECLSPEC_HOTPATCH GetKeyState(INT vkey)
748 {
749     SHORT retval = 0;
750
751     SERVER_START_REQ( get_key_state )
752     {
753         req->tid = GetCurrentThreadId();
754         req->key = vkey;
755         if (!wine_server_call( req )) retval = (signed char)reply->state;
756     }
757     SERVER_END_REQ;
758     TRACE("key (0x%x) -> %x\n", vkey, retval);
759     return retval;
760 }
761
762
763 /**********************************************************************
764  *              GetKeyboardState (USER32.@)
765  */
766 BOOL WINAPI DECLSPEC_HOTPATCH GetKeyboardState( LPBYTE state )
767 {
768     BOOL ret;
769
770     TRACE("(%p)\n", state);
771
772     memset( state, 0, 256 );
773     SERVER_START_REQ( get_key_state )
774     {
775         req->tid = GetCurrentThreadId();
776         req->key = -1;
777         wine_server_set_reply( req, state, 256 );
778         ret = !wine_server_call_err( req );
779     }
780     SERVER_END_REQ;
781     return ret;
782 }
783
784
785 /**********************************************************************
786  *              SetKeyboardState (USER32.@)
787  */
788 BOOL WINAPI SetKeyboardState( LPBYTE state )
789 {
790     BOOL ret;
791
792     SERVER_START_REQ( set_key_state )
793     {
794         req->tid = GetCurrentThreadId();
795         wine_server_add_data( req, state, 256 );
796         ret = !wine_server_call_err( req );
797     }
798     SERVER_END_REQ;
799     return ret;
800 }
801
802
803 /**********************************************************************
804  *              VkKeyScanA (USER32.@)
805  *
806  * VkKeyScan translates an ANSI character to a virtual-key and shift code
807  * for the current keyboard.
808  * high-order byte yields :
809  *      0       Unshifted
810  *      1       Shift
811  *      2       Ctrl
812  *      3-5     Shift-key combinations that are not used for characters
813  *      6       Ctrl-Alt
814  *      7       Ctrl-Alt-Shift
815  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
816  * FIXME : works ok except for dead chars :
817  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
818  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
819  */
820 SHORT WINAPI VkKeyScanA(CHAR cChar)
821 {
822     WCHAR wChar;
823
824     if (IsDBCSLeadByte(cChar)) return -1;
825
826     MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
827     return VkKeyScanW(wChar);
828 }
829
830 /******************************************************************************
831  *              VkKeyScanW (USER32.@)
832  */
833 SHORT WINAPI VkKeyScanW(WCHAR cChar)
834 {
835     return VkKeyScanExW(cChar, GetKeyboardLayout(0));
836 }
837
838 /**********************************************************************
839  *              VkKeyScanExA (USER32.@)
840  */
841 WORD WINAPI VkKeyScanExA(CHAR cChar, HKL dwhkl)
842 {
843     WCHAR wChar;
844
845     if (IsDBCSLeadByte(cChar)) return -1;
846
847     MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
848     return VkKeyScanExW(wChar, dwhkl);
849 }
850
851 /******************************************************************************
852  *              VkKeyScanExW (USER32.@)
853  */
854 WORD WINAPI VkKeyScanExW(WCHAR cChar, HKL dwhkl)
855 {
856     return USER_Driver->pVkKeyScanEx(cChar, dwhkl);
857 }
858
859 /**********************************************************************
860  *              OemKeyScan (USER32.@)
861  */
862 DWORD WINAPI OemKeyScan(WORD wOemChar)
863 {
864     return wOemChar;
865 }
866
867 /******************************************************************************
868  *              GetKeyboardType (USER32.@)
869  */
870 INT WINAPI GetKeyboardType(INT nTypeFlag)
871 {
872     TRACE_(keyboard)("(%d)\n", nTypeFlag);
873     switch(nTypeFlag)
874     {
875     case 0:      /* Keyboard type */
876         return 4;    /* AT-101 */
877     case 1:      /* Keyboard Subtype */
878         return 0;    /* There are no defined subtypes */
879     case 2:      /* Number of F-keys */
880         return 12;   /* We're doing an 101 for now, so return 12 F-keys */
881     default:
882         WARN_(keyboard)("Unknown type\n");
883         return 0;    /* The book says 0 here, so 0 */
884     }
885 }
886
887 /******************************************************************************
888  *              MapVirtualKeyA (USER32.@)
889  */
890 UINT WINAPI MapVirtualKeyA(UINT code, UINT maptype)
891 {
892     return MapVirtualKeyExA( code, maptype, GetKeyboardLayout(0) );
893 }
894
895 /******************************************************************************
896  *              MapVirtualKeyW (USER32.@)
897  */
898 UINT WINAPI MapVirtualKeyW(UINT code, UINT maptype)
899 {
900     return MapVirtualKeyExW(code, maptype, GetKeyboardLayout(0));
901 }
902
903 /******************************************************************************
904  *              MapVirtualKeyExA (USER32.@)
905  */
906 UINT WINAPI MapVirtualKeyExA(UINT code, UINT maptype, HKL hkl)
907 {
908     UINT ret;
909
910     ret = MapVirtualKeyExW( code, maptype, hkl );
911     if (maptype == MAPVK_VK_TO_CHAR)
912     {
913         BYTE ch = 0;
914         WCHAR wch = ret;
915
916         WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)&ch, 1, NULL, NULL );
917         ret = ch;
918     }
919     return ret;
920 }
921
922 /******************************************************************************
923  *              MapVirtualKeyExW (USER32.@)
924  */
925 UINT WINAPI MapVirtualKeyExW(UINT code, UINT maptype, HKL hkl)
926 {
927     TRACE_(keyboard)("(%X, %d, %p)\n", code, maptype, hkl);
928
929     return USER_Driver->pMapVirtualKeyEx(code, maptype, hkl);
930 }
931
932 /****************************************************************************
933  *              GetKBCodePage (USER32.@)
934  */
935 UINT WINAPI GetKBCodePage(void)
936 {
937     return GetOEMCP();
938 }
939
940 /***********************************************************************
941  *              GetKeyboardLayout (USER32.@)
942  *
943  *        - device handle for keyboard layout defaulted to
944  *          the language id. This is the way Windows default works.
945  *        - the thread identifier is also ignored.
946  */
947 HKL WINAPI GetKeyboardLayout(DWORD thread_id)
948 {
949     return USER_Driver->pGetKeyboardLayout(thread_id);
950 }
951
952 /****************************************************************************
953  *              GetKeyboardLayoutNameA (USER32.@)
954  */
955 BOOL WINAPI GetKeyboardLayoutNameA(LPSTR pszKLID)
956 {
957     WCHAR buf[KL_NAMELENGTH];
958
959     if (GetKeyboardLayoutNameW(buf))
960         return WideCharToMultiByte( CP_ACP, 0, buf, -1, pszKLID, KL_NAMELENGTH, NULL, NULL ) != 0;
961     return FALSE;
962 }
963
964 /****************************************************************************
965  *              GetKeyboardLayoutNameW (USER32.@)
966  */
967 BOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID)
968 {
969     return USER_Driver->pGetKeyboardLayoutName(pwszKLID);
970 }
971
972 /****************************************************************************
973  *              GetKeyNameTextA (USER32.@)
974  */
975 INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize)
976 {
977     WCHAR buf[256];
978     INT ret;
979
980     if (!nSize || !GetKeyNameTextW(lParam, buf, 256))
981     {
982         lpBuffer[0] = 0;
983         return 0;
984     }
985     ret = WideCharToMultiByte(CP_ACP, 0, buf, -1, lpBuffer, nSize, NULL, NULL);
986     if (!ret && nSize)
987     {
988         ret = nSize - 1;
989         lpBuffer[ret] = 0;
990     }
991     else ret--;
992
993     return ret;
994 }
995
996 /****************************************************************************
997  *              GetKeyNameTextW (USER32.@)
998  */
999 INT WINAPI GetKeyNameTextW(LONG lParam, LPWSTR lpBuffer, INT nSize)
1000 {
1001     if (!lpBuffer || !nSize) return 0;
1002     return USER_Driver->pGetKeyNameText( lParam, lpBuffer, nSize );
1003 }
1004
1005 /****************************************************************************
1006  *              ToUnicode (USER32.@)
1007  */
1008 INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1009                      LPWSTR lpwStr, int size, UINT flags)
1010 {
1011     return ToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, GetKeyboardLayout(0));
1012 }
1013
1014 /****************************************************************************
1015  *              ToUnicodeEx (USER32.@)
1016  */
1017 INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1018                        LPWSTR lpwStr, int size, UINT flags, HKL hkl)
1019 {
1020     return USER_Driver->pToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, hkl);
1021 }
1022
1023 /****************************************************************************
1024  *              ToAscii (USER32.@)
1025  */
1026 INT WINAPI ToAscii( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1027                     LPWORD lpChar, UINT flags )
1028 {
1029     return ToAsciiEx(virtKey, scanCode, lpKeyState, lpChar, flags, GetKeyboardLayout(0));
1030 }
1031
1032 /****************************************************************************
1033  *              ToAsciiEx (USER32.@)
1034  */
1035 INT WINAPI ToAsciiEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
1036                       LPWORD lpChar, UINT flags, HKL dwhkl )
1037 {
1038     WCHAR uni_chars[2];
1039     INT ret, n_ret;
1040
1041     ret = ToUnicodeEx(virtKey, scanCode, lpKeyState, uni_chars, 2, flags, dwhkl);
1042     if (ret < 0) n_ret = 1; /* FIXME: make ToUnicode return 2 for dead chars */
1043     else n_ret = ret;
1044     WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL);
1045     return ret;
1046 }
1047
1048 /**********************************************************************
1049  *              ActivateKeyboardLayout (USER32.@)
1050  */
1051 HKL WINAPI ActivateKeyboardLayout(HKL hLayout, UINT flags)
1052 {
1053     TRACE_(keyboard)("(%p, %d)\n", hLayout, flags);
1054
1055     return USER_Driver->pActivateKeyboardLayout(hLayout, flags);
1056 }
1057
1058 /**********************************************************************
1059  *              BlockInput (USER32.@)
1060  */
1061 BOOL WINAPI BlockInput(BOOL fBlockIt)
1062 {
1063     FIXME_(keyboard)("(%d): stub\n", fBlockIt);
1064     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1065
1066     return FALSE;
1067 }
1068
1069 /***********************************************************************
1070  *              GetKeyboardLayoutList (USER32.@)
1071  *
1072  * Return number of values available if either input parm is
1073  *  0, per MS documentation.
1074  */
1075 UINT WINAPI GetKeyboardLayoutList(INT nBuff, HKL *layouts)
1076 {
1077     HKEY hKeyKeyboard;
1078     DWORD rc;
1079     INT count = 0;
1080     ULONG_PTR baselayout;
1081     LANGID langid;
1082     static const WCHAR szKeyboardReg[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s',0};
1083
1084     TRACE_(keyboard)("(%d,%p)\n",nBuff,layouts);
1085
1086     baselayout = GetUserDefaultLCID();
1087     langid = PRIMARYLANGID(LANGIDFROMLCID(baselayout));
1088     if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1089         baselayout |= 0xe001 << 16; /* IME */
1090     else
1091         baselayout |= baselayout << 16;
1092
1093     /* Enumerate the Registry */
1094     rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,szKeyboardReg,&hKeyKeyboard);
1095     if (rc == ERROR_SUCCESS)
1096     {
1097         do {
1098             WCHAR szKeyName[9];
1099             HKL layout;
1100             rc = RegEnumKeyW(hKeyKeyboard, count, szKeyName, 9);
1101             if (rc == ERROR_SUCCESS)
1102             {
1103                 layout = (HKL)(ULONG_PTR)strtoulW(szKeyName,NULL,16);
1104                 if (baselayout != 0 && layout == (HKL)baselayout)
1105                     baselayout = 0; /* found in the registry do not add again */
1106                 if (nBuff && layouts)
1107                 {
1108                     if (count >= nBuff ) break;
1109                     layouts[count] = layout;
1110                 }
1111                 count ++;
1112             }
1113         } while (rc == ERROR_SUCCESS);
1114         RegCloseKey(hKeyKeyboard);
1115     }
1116
1117     /* make sure our base layout is on the list */
1118     if (baselayout != 0)
1119     {
1120         if (nBuff && layouts)
1121         {
1122             if (count < nBuff)
1123             {
1124                 layouts[count] = (HKL)baselayout;
1125                 count++;
1126             }
1127         }
1128         else
1129             count++;
1130     }
1131
1132     return count;
1133 }
1134
1135
1136 /***********************************************************************
1137  *              RegisterHotKey (USER32.@)
1138  */
1139 BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
1140 {
1141     BOOL ret;
1142     int replaced=0;
1143
1144     TRACE_(keyboard)("(%p,%d,0x%08x,%X)\n",hwnd,id,modifiers,vk);
1145
1146     if ((hwnd == NULL || WIN_IsCurrentThread(hwnd)) &&
1147         !USER_Driver->pRegisterHotKey(hwnd, modifiers, vk))
1148         return FALSE;
1149
1150     SERVER_START_REQ( register_hotkey )
1151     {
1152         req->window = wine_server_user_handle( hwnd );
1153         req->id = id;
1154         req->flags = modifiers;
1155         req->vkey = vk;
1156         if ((ret = !wine_server_call_err( req )))
1157         {
1158             replaced = reply->replaced;
1159             modifiers = reply->flags;
1160             vk = reply->vkey;
1161         }
1162     }
1163     SERVER_END_REQ;
1164
1165     if (ret && replaced)
1166         USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1167
1168     return ret;
1169 }
1170
1171 /***********************************************************************
1172  *              UnregisterHotKey (USER32.@)
1173  */
1174 BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id)
1175 {
1176     BOOL ret;
1177     UINT modifiers, vk;
1178
1179     TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
1180
1181     SERVER_START_REQ( unregister_hotkey )
1182     {
1183         req->window = wine_server_user_handle( hwnd );
1184         req->id = id;
1185         if ((ret = !wine_server_call_err( req )))
1186         {
1187             modifiers = reply->flags;
1188             vk = reply->vkey;
1189         }
1190     }
1191     SERVER_END_REQ;
1192
1193     if (ret)
1194         USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1195
1196     return ret;
1197 }
1198
1199 /***********************************************************************
1200  *              LoadKeyboardLayoutW (USER32.@)
1201  */
1202 HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID, UINT Flags)
1203 {
1204     TRACE_(keyboard)("(%s, %d)\n", debugstr_w(pwszKLID), Flags);
1205
1206     return USER_Driver->pLoadKeyboardLayout(pwszKLID, Flags);
1207 }
1208
1209 /***********************************************************************
1210  *              LoadKeyboardLayoutA (USER32.@)
1211  */
1212 HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID, UINT Flags)
1213 {
1214     HKL ret;
1215     UNICODE_STRING pwszKLIDW;
1216
1217     if (pwszKLID) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW, pwszKLID);
1218     else pwszKLIDW.Buffer = NULL;
1219
1220     ret = LoadKeyboardLayoutW(pwszKLIDW.Buffer, Flags);
1221     RtlFreeUnicodeString(&pwszKLIDW);
1222     return ret;
1223 }
1224
1225
1226 /***********************************************************************
1227  *              UnloadKeyboardLayout (USER32.@)
1228  */
1229 BOOL WINAPI UnloadKeyboardLayout(HKL hkl)
1230 {
1231     TRACE_(keyboard)("(%p)\n", hkl);
1232
1233     return USER_Driver->pUnloadKeyboardLayout(hkl);
1234 }
1235
1236 typedef struct __TRACKINGLIST {
1237     TRACKMOUSEEVENT tme;
1238     POINT pos; /* center of hover rectangle */
1239 } _TRACKINGLIST;
1240
1241 /* FIXME: move tracking stuff into a per thread data */
1242 static _TRACKINGLIST tracking_info;
1243 static UINT_PTR timer;
1244
1245 static void check_mouse_leave(HWND hwnd, int hittest)
1246 {
1247     if (tracking_info.tme.hwndTrack != hwnd)
1248     {
1249         if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1250             PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
1251         else
1252             PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
1253
1254         /* remove the TME_LEAVE flag */
1255         tracking_info.tme.dwFlags &= ~TME_LEAVE;
1256     }
1257     else
1258     {
1259         if (hittest == HTCLIENT)
1260         {
1261             if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1262             {
1263                 PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
1264                 /* remove the TME_LEAVE flag */
1265                 tracking_info.tme.dwFlags &= ~TME_LEAVE;
1266             }
1267         }
1268         else
1269         {
1270             if (!(tracking_info.tme.dwFlags & TME_NONCLIENT))
1271             {
1272                 PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
1273                 /* remove the TME_LEAVE flag */
1274                 tracking_info.tme.dwFlags &= ~TME_LEAVE;
1275             }
1276         }
1277     }
1278 }
1279
1280 static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
1281                                          DWORD dwTime)
1282 {
1283     POINT pos;
1284     INT hoverwidth = 0, hoverheight = 0, hittest;
1285
1286     TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd, uMsg, idEvent, dwTime);
1287
1288     GetCursorPos(&pos);
1289     hwnd = WINPOS_WindowFromPoint(hwnd, pos, &hittest);
1290
1291     TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1292
1293     SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
1294     SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
1295
1296     TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1297            wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
1298            hoverwidth, hoverheight);
1299
1300     /* see if this tracking event is looking for TME_LEAVE and that the */
1301     /* mouse has left the window */
1302     if (tracking_info.tme.dwFlags & TME_LEAVE)
1303     {
1304         check_mouse_leave(hwnd, hittest);
1305     }
1306
1307     if (tracking_info.tme.hwndTrack != hwnd)
1308     {
1309         /* mouse is gone, stop tracking mouse hover */
1310         tracking_info.tme.dwFlags &= ~TME_HOVER;
1311     }
1312
1313     /* see if we are tracking hovering for this hwnd */
1314     if (tracking_info.tme.dwFlags & TME_HOVER)
1315     {
1316         /* has the cursor moved outside the rectangle centered around pos? */
1317         if ((abs(pos.x - tracking_info.pos.x) > (hoverwidth / 2)) ||
1318             (abs(pos.y - tracking_info.pos.y) > (hoverheight / 2)))
1319         {
1320             /* record this new position as the current position */
1321             tracking_info.pos = pos;
1322         }
1323         else
1324         {
1325             if (hittest == HTCLIENT)
1326             {
1327                 ScreenToClient(hwnd, &pos);
1328                 TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos));
1329
1330                 PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSEHOVER,
1331                              get_key_state(), MAKELPARAM( pos.x, pos.y ));
1332             }
1333             else
1334             {
1335                 if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1336                     PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSEHOVER,
1337                                  hittest, MAKELPARAM( pos.x, pos.y ));
1338             }
1339
1340             /* stop tracking mouse hover */
1341             tracking_info.tme.dwFlags &= ~TME_HOVER;
1342         }
1343     }
1344
1345     /* stop the timer if the tracking list is empty */
1346     if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
1347     {
1348         KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1349         timer = 0;
1350         tracking_info.tme.hwndTrack = 0;
1351         tracking_info.tme.dwFlags = 0;
1352         tracking_info.tme.dwHoverTime = 0;
1353     }
1354 }
1355
1356
1357 /***********************************************************************
1358  * TrackMouseEvent [USER32]
1359  *
1360  * Requests notification of mouse events
1361  *
1362  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1363  * to the hwnd specified in the ptme structure.  After the event message
1364  * is posted to the hwnd, the entry in the queue is removed.
1365  *
1366  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1367  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1368  * immediately and the TME_LEAVE flag being ignored.
1369  *
1370  * PARAMS
1371  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1372  *
1373  * RETURNS
1374  *     Success: non-zero
1375  *     Failure: zero
1376  *
1377  */
1378
1379 BOOL WINAPI
1380 TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1381 {
1382     HWND hwnd;
1383     POINT pos;
1384     DWORD hover_time;
1385     INT hittest;
1386
1387     TRACE("%x, %x, %p, %u\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
1388
1389     if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
1390         WARN("wrong TRACKMOUSEEVENT size from app\n");
1391         SetLastError(ERROR_INVALID_PARAMETER);
1392         return FALSE;
1393     }
1394
1395     /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1396     if (ptme->dwFlags & TME_QUERY )
1397     {
1398         *ptme = tracking_info.tme;
1399         /* set cbSize in the case it's not initialized yet */
1400         ptme->cbSize = sizeof(TRACKMOUSEEVENT);
1401
1402         return TRUE; /* return here, TME_QUERY is retrieving information */
1403     }
1404
1405     if (!IsWindow(ptme->hwndTrack))
1406     {
1407         SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1408         return FALSE;
1409     }
1410
1411     hover_time = (ptme->dwFlags & TME_HOVER) ? ptme->dwHoverTime : HOVER_DEFAULT;
1412
1413     /* if HOVER_DEFAULT was specified replace this with the system's current value.
1414      * TME_LEAVE doesn't need to specify hover time so use default */
1415     if (hover_time == HOVER_DEFAULT || hover_time == 0)
1416         SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
1417
1418     GetCursorPos(&pos);
1419     hwnd = WINPOS_WindowFromPoint(ptme->hwndTrack, pos, &hittest);
1420     TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1421
1422     if (ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
1423         FIXME("Unknown flag(s) %08x\n", ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT));
1424
1425     if (ptme->dwFlags & TME_CANCEL)
1426     {
1427         if (tracking_info.tme.hwndTrack == ptme->hwndTrack)
1428         {
1429             tracking_info.tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1430
1431             /* if we aren't tracking on hover or leave remove this entry */
1432             if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
1433             {
1434                 KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1435                 timer = 0;
1436                 tracking_info.tme.hwndTrack = 0;
1437                 tracking_info.tme.dwFlags = 0;
1438                 tracking_info.tme.dwHoverTime = 0;
1439             }
1440         }
1441     } else {
1442         /* In our implementation it's possible that another window will receive a
1443          * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1444          * called. In such a situation post the WM_MOUSELEAVE now */
1445         if (tracking_info.tme.dwFlags & TME_LEAVE && tracking_info.tme.hwndTrack != NULL)
1446             check_mouse_leave(hwnd, hittest);
1447
1448         if (timer)
1449         {
1450             KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1451             timer = 0;
1452             tracking_info.tme.hwndTrack = 0;
1453             tracking_info.tme.dwFlags = 0;
1454             tracking_info.tme.dwHoverTime = 0;
1455         }
1456
1457         if (ptme->hwndTrack == hwnd)
1458         {
1459             /* Adding new mouse event to the tracking list */
1460             tracking_info.tme = *ptme;
1461             tracking_info.tme.dwHoverTime = hover_time;
1462
1463             /* Initialize HoverInfo variables even if not hover tracking */
1464             tracking_info.pos = pos;
1465
1466             timer = SetSystemTimer(tracking_info.tme.hwndTrack, (UINT_PTR)&tracking_info.tme, hover_time, TrackMouseEventProc);
1467         }
1468     }
1469
1470     return TRUE;
1471 }
1472
1473 /***********************************************************************
1474  * GetMouseMovePointsEx [USER32]
1475  *
1476  * RETURNS
1477  *     Success: count of point set in the buffer
1478  *     Failure: -1
1479  */
1480 int WINAPI GetMouseMovePointsEx(UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPOINT ptout, int count, DWORD res) {
1481
1482     if((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > 64)) {
1483         SetLastError(ERROR_INVALID_PARAMETER);
1484         return -1;
1485     }
1486
1487     if(!ptin || (!ptout && count)) {
1488         SetLastError(ERROR_NOACCESS);
1489         return -1;
1490     }
1491
1492     FIXME("(%d %p %p %d %d) stub\n", size, ptin, ptout, count, res);
1493
1494     SetLastError(ERROR_POINT_NOT_FOUND);
1495     return -1;
1496 }