winex11: Move the icon window off-screen for managed windows.
[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(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize)
482 {
483     FIXME("(pRawInputDeviceList=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDeviceList, puiNumDevices, cbSize);
484
485     if(pRawInputDeviceList)
486         memset(pRawInputDeviceList, 0, sizeof *pRawInputDeviceList);
487     *puiNumDevices = 0;
488     return 0;
489 }
490
491
492 /******************************************************************
493 *               RegisterRawInputDevices (USER32.@)
494 */
495 BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
496 {
497     struct rawinput_device *d;
498     BOOL ret;
499     UINT i;
500
501     TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
502
503     if (size != sizeof(*devices))
504     {
505         WARN("Invalid structure size %u.\n", size);
506         return FALSE;
507     }
508
509     if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;
510
511     for (i = 0; i < device_count; ++i)
512     {
513         TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
514                 i, devices[i].usUsagePage, devices[i].usUsage,
515                 devices[i].dwFlags, devices[i].hwndTarget);
516         if (devices[i].dwFlags & ~RIDEV_REMOVE)
517             FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
518
519         d[i].usage_page = devices[i].usUsagePage;
520         d[i].usage = devices[i].usUsage;
521         d[i].flags = devices[i].dwFlags;
522         d[i].target = wine_server_user_handle( devices[i].hwndTarget );
523     }
524
525     SERVER_START_REQ( update_rawinput_devices )
526     {
527         wine_server_add_data( req, d, device_count * sizeof(*d) );
528         ret = !wine_server_call( req );
529     }
530     SERVER_END_REQ;
531
532     HeapFree( GetProcessHeap(), 0, d );
533
534     return ret;
535 }
536
537
538 /******************************************************************
539 *               GetRawInputData (USER32.@)
540 */
541 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
542 {
543     RAWINPUT *ri = (RAWINPUT *)rawinput;
544     UINT s;
545
546     TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
547             rawinput, command, data, data_size, header_size);
548
549     if (header_size != sizeof(RAWINPUTHEADER))
550     {
551         WARN("Invalid structure size %u.\n", header_size);
552         return ~0U;
553     }
554
555     switch (command)
556     {
557     case RID_INPUT:
558         s = ri->header.dwSize;
559         break;
560     case RID_HEADER:
561         s = sizeof(RAWINPUTHEADER);
562         break;
563     default:
564         return ~0U;
565     }
566
567     if (!data)
568     {
569         *data_size = s;
570         return 0;
571     }
572
573     if (*data_size < s) return ~0U;
574     memcpy(data, ri, s);
575     return s;
576 }
577
578
579 /******************************************************************
580 *               GetRawInputBuffer (USER32.@)
581 */
582 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
583 {
584     FIXME("(pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n", pData, pcbSize, cbSizeHeader);
585
586     return 0;
587 }
588
589
590 /******************************************************************
591 *               GetRawInputDeviceInfoA (USER32.@)
592 */
593 UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
594 {
595     FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);
596
597     return 0;
598 }
599
600
601 /******************************************************************
602 *               GetRawInputDeviceInfoW (USER32.@)
603 */
604 UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
605 {
606     FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);
607
608     return 0;
609 }
610
611
612 /******************************************************************
613 *               GetRegisteredRawInputDevices (USER32.@)
614 */
615 UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize)
616 {
617     FIXME("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDevices, puiNumDevices, cbSize);
618
619     return 0;
620 }
621
622
623 /******************************************************************
624 *               DefRawInputProc (USER32.@)
625 */
626 LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput, INT nInput, UINT cbSizeHeader)
627 {
628     FIXME("(paRawInput=%p, nInput=%d, cbSizeHeader=%d) stub!\n", *paRawInput, nInput, cbSizeHeader);
629
630     return 0;
631 }
632
633
634 /**********************************************************************
635  *              AttachThreadInput (USER32.@)
636  *
637  * Attaches the input processing mechanism of one thread to that of
638  * another thread.
639  */
640 BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
641 {
642     BOOL ret;
643
644     SERVER_START_REQ( attach_thread_input )
645     {
646         req->tid_from = from;
647         req->tid_to   = to;
648         req->attach   = attach;
649         ret = !wine_server_call_err( req );
650     }
651     SERVER_END_REQ;
652     return ret;
653 }
654
655
656 /**********************************************************************
657  *              GetKeyState (USER32.@)
658  *
659  * An application calls the GetKeyState function in response to a
660  * keyboard-input message.  This function retrieves the state of the key
661  * at the time the input message was generated.
662  */
663 SHORT WINAPI DECLSPEC_HOTPATCH GetKeyState(INT vkey)
664 {
665     SHORT retval = 0;
666
667     SERVER_START_REQ( get_key_state )
668     {
669         req->tid = GetCurrentThreadId();
670         req->key = vkey;
671         if (!wine_server_call( req )) retval = (signed char)reply->state;
672     }
673     SERVER_END_REQ;
674     TRACE("key (0x%x) -> %x\n", vkey, retval);
675     return retval;
676 }
677
678
679 /**********************************************************************
680  *              GetKeyboardState (USER32.@)
681  */
682 BOOL WINAPI DECLSPEC_HOTPATCH GetKeyboardState( LPBYTE state )
683 {
684     BOOL ret;
685
686     TRACE("(%p)\n", state);
687
688     memset( state, 0, 256 );
689     SERVER_START_REQ( get_key_state )
690     {
691         req->tid = GetCurrentThreadId();
692         req->key = -1;
693         wine_server_set_reply( req, state, 256 );
694         ret = !wine_server_call_err( req );
695     }
696     SERVER_END_REQ;
697     return ret;
698 }
699
700
701 /**********************************************************************
702  *              SetKeyboardState (USER32.@)
703  */
704 BOOL WINAPI SetKeyboardState( LPBYTE state )
705 {
706     BOOL ret;
707
708     SERVER_START_REQ( set_key_state )
709     {
710         req->tid = GetCurrentThreadId();
711         wine_server_add_data( req, state, 256 );
712         ret = !wine_server_call_err( req );
713     }
714     SERVER_END_REQ;
715     return ret;
716 }
717
718
719 /**********************************************************************
720  *              VkKeyScanA (USER32.@)
721  *
722  * VkKeyScan translates an ANSI character to a virtual-key and shift code
723  * for the current keyboard.
724  * high-order byte yields :
725  *      0       Unshifted
726  *      1       Shift
727  *      2       Ctrl
728  *      3-5     Shift-key combinations that are not used for characters
729  *      6       Ctrl-Alt
730  *      7       Ctrl-Alt-Shift
731  *      I.e. :  Shift = 1, Ctrl = 2, Alt = 4.
732  * FIXME : works ok except for dead chars :
733  * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
734  * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
735  */
736 SHORT WINAPI VkKeyScanA(CHAR cChar)
737 {
738     WCHAR wChar;
739
740     if (IsDBCSLeadByte(cChar)) return -1;
741
742     MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
743     return VkKeyScanW(wChar);
744 }
745
746 /******************************************************************************
747  *              VkKeyScanW (USER32.@)
748  */
749 SHORT WINAPI VkKeyScanW(WCHAR cChar)
750 {
751     return VkKeyScanExW(cChar, GetKeyboardLayout(0));
752 }
753
754 /**********************************************************************
755  *              VkKeyScanExA (USER32.@)
756  */
757 WORD WINAPI VkKeyScanExA(CHAR cChar, HKL dwhkl)
758 {
759     WCHAR wChar;
760
761     if (IsDBCSLeadByte(cChar)) return -1;
762
763     MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
764     return VkKeyScanExW(wChar, dwhkl);
765 }
766
767 /******************************************************************************
768  *              VkKeyScanExW (USER32.@)
769  */
770 WORD WINAPI VkKeyScanExW(WCHAR cChar, HKL dwhkl)
771 {
772     return USER_Driver->pVkKeyScanEx(cChar, dwhkl);
773 }
774
775 /**********************************************************************
776  *              OemKeyScan (USER32.@)
777  */
778 DWORD WINAPI OemKeyScan(WORD wOemChar)
779 {
780     return wOemChar;
781 }
782
783 /******************************************************************************
784  *              GetKeyboardType (USER32.@)
785  */
786 INT WINAPI GetKeyboardType(INT nTypeFlag)
787 {
788     TRACE_(keyboard)("(%d)\n", nTypeFlag);
789     switch(nTypeFlag)
790     {
791     case 0:      /* Keyboard type */
792         return 4;    /* AT-101 */
793     case 1:      /* Keyboard Subtype */
794         return 0;    /* There are no defined subtypes */
795     case 2:      /* Number of F-keys */
796         return 12;   /* We're doing an 101 for now, so return 12 F-keys */
797     default:
798         WARN_(keyboard)("Unknown type\n");
799         return 0;    /* The book says 0 here, so 0 */
800     }
801 }
802
803 /******************************************************************************
804  *              MapVirtualKeyA (USER32.@)
805  */
806 UINT WINAPI MapVirtualKeyA(UINT code, UINT maptype)
807 {
808     return MapVirtualKeyExA( code, maptype, GetKeyboardLayout(0) );
809 }
810
811 /******************************************************************************
812  *              MapVirtualKeyW (USER32.@)
813  */
814 UINT WINAPI MapVirtualKeyW(UINT code, UINT maptype)
815 {
816     return MapVirtualKeyExW(code, maptype, GetKeyboardLayout(0));
817 }
818
819 /******************************************************************************
820  *              MapVirtualKeyExA (USER32.@)
821  */
822 UINT WINAPI MapVirtualKeyExA(UINT code, UINT maptype, HKL hkl)
823 {
824     UINT ret;
825
826     ret = MapVirtualKeyExW( code, maptype, hkl );
827     if (maptype == MAPVK_VK_TO_CHAR)
828     {
829         BYTE ch = 0;
830         WCHAR wch = ret;
831
832         WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)&ch, 1, NULL, NULL );
833         ret = ch;
834     }
835     return ret;
836 }
837
838 /******************************************************************************
839  *              MapVirtualKeyExW (USER32.@)
840  */
841 UINT WINAPI MapVirtualKeyExW(UINT code, UINT maptype, HKL hkl)
842 {
843     TRACE_(keyboard)("(%X, %d, %p)\n", code, maptype, hkl);
844
845     return USER_Driver->pMapVirtualKeyEx(code, maptype, hkl);
846 }
847
848 /****************************************************************************
849  *              GetKBCodePage (USER32.@)
850  */
851 UINT WINAPI GetKBCodePage(void)
852 {
853     return GetOEMCP();
854 }
855
856 /***********************************************************************
857  *              GetKeyboardLayout (USER32.@)
858  *
859  *        - device handle for keyboard layout defaulted to
860  *          the language id. This is the way Windows default works.
861  *        - the thread identifier is also ignored.
862  */
863 HKL WINAPI GetKeyboardLayout(DWORD thread_id)
864 {
865     return USER_Driver->pGetKeyboardLayout(thread_id);
866 }
867
868 /****************************************************************************
869  *              GetKeyboardLayoutNameA (USER32.@)
870  */
871 BOOL WINAPI GetKeyboardLayoutNameA(LPSTR pszKLID)
872 {
873     WCHAR buf[KL_NAMELENGTH];
874
875     if (GetKeyboardLayoutNameW(buf))
876         return WideCharToMultiByte( CP_ACP, 0, buf, -1, pszKLID, KL_NAMELENGTH, NULL, NULL ) != 0;
877     return FALSE;
878 }
879
880 /****************************************************************************
881  *              GetKeyboardLayoutNameW (USER32.@)
882  */
883 BOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID)
884 {
885     return USER_Driver->pGetKeyboardLayoutName(pwszKLID);
886 }
887
888 /****************************************************************************
889  *              GetKeyNameTextA (USER32.@)
890  */
891 INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize)
892 {
893     WCHAR buf[256];
894     INT ret;
895
896     if (!nSize || !GetKeyNameTextW(lParam, buf, 256))
897     {
898         lpBuffer[0] = 0;
899         return 0;
900     }
901     ret = WideCharToMultiByte(CP_ACP, 0, buf, -1, lpBuffer, nSize, NULL, NULL);
902     if (!ret && nSize)
903     {
904         ret = nSize - 1;
905         lpBuffer[ret] = 0;
906     }
907     else ret--;
908
909     return ret;
910 }
911
912 /****************************************************************************
913  *              GetKeyNameTextW (USER32.@)
914  */
915 INT WINAPI GetKeyNameTextW(LONG lParam, LPWSTR lpBuffer, INT nSize)
916 {
917     if (!lpBuffer || !nSize) return 0;
918     return USER_Driver->pGetKeyNameText( lParam, lpBuffer, nSize );
919 }
920
921 /****************************************************************************
922  *              ToUnicode (USER32.@)
923  */
924 INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
925                      LPWSTR lpwStr, int size, UINT flags)
926 {
927     return ToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, GetKeyboardLayout(0));
928 }
929
930 /****************************************************************************
931  *              ToUnicodeEx (USER32.@)
932  */
933 INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
934                        LPWSTR lpwStr, int size, UINT flags, HKL hkl)
935 {
936     return USER_Driver->pToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, hkl);
937 }
938
939 /****************************************************************************
940  *              ToAscii (USER32.@)
941  */
942 INT WINAPI ToAscii( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
943                     LPWORD lpChar, UINT flags )
944 {
945     return ToAsciiEx(virtKey, scanCode, lpKeyState, lpChar, flags, GetKeyboardLayout(0));
946 }
947
948 /****************************************************************************
949  *              ToAsciiEx (USER32.@)
950  */
951 INT WINAPI ToAsciiEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
952                       LPWORD lpChar, UINT flags, HKL dwhkl )
953 {
954     WCHAR uni_chars[2];
955     INT ret, n_ret;
956
957     ret = ToUnicodeEx(virtKey, scanCode, lpKeyState, uni_chars, 2, flags, dwhkl);
958     if (ret < 0) n_ret = 1; /* FIXME: make ToUnicode return 2 for dead chars */
959     else n_ret = ret;
960     WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL);
961     return ret;
962 }
963
964 /**********************************************************************
965  *              ActivateKeyboardLayout (USER32.@)
966  */
967 HKL WINAPI ActivateKeyboardLayout(HKL hLayout, UINT flags)
968 {
969     TRACE_(keyboard)("(%p, %d)\n", hLayout, flags);
970
971     return USER_Driver->pActivateKeyboardLayout(hLayout, flags);
972 }
973
974 /**********************************************************************
975  *              BlockInput (USER32.@)
976  */
977 BOOL WINAPI BlockInput(BOOL fBlockIt)
978 {
979     FIXME_(keyboard)("(%d): stub\n", fBlockIt);
980     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
981
982     return FALSE;
983 }
984
985 /***********************************************************************
986  *              GetKeyboardLayoutList (USER32.@)
987  *
988  * Return number of values available if either input parm is
989  *  0, per MS documentation.
990  */
991 UINT WINAPI GetKeyboardLayoutList(INT nBuff, HKL *layouts)
992 {
993     HKEY hKeyKeyboard;
994     DWORD rc;
995     INT count = 0;
996     ULONG_PTR baselayout;
997     LANGID langid;
998     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};
999
1000     TRACE_(keyboard)("(%d,%p)\n",nBuff,layouts);
1001
1002     baselayout = GetUserDefaultLCID();
1003     langid = PRIMARYLANGID(LANGIDFROMLCID(baselayout));
1004     if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
1005         baselayout |= 0xe001 << 16; /* IME */
1006     else
1007         baselayout |= baselayout << 16;
1008
1009     /* Enumerate the Registry */
1010     rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,szKeyboardReg,&hKeyKeyboard);
1011     if (rc == ERROR_SUCCESS)
1012     {
1013         do {
1014             WCHAR szKeyName[9];
1015             HKL layout;
1016             rc = RegEnumKeyW(hKeyKeyboard, count, szKeyName, 9);
1017             if (rc == ERROR_SUCCESS)
1018             {
1019                 layout = (HKL)(ULONG_PTR)strtoulW(szKeyName,NULL,16);
1020                 if (baselayout != 0 && layout == (HKL)baselayout)
1021                     baselayout = 0; /* found in the registry do not add again */
1022                 if (nBuff && layouts)
1023                 {
1024                     if (count >= nBuff ) break;
1025                     layouts[count] = layout;
1026                 }
1027                 count ++;
1028             }
1029         } while (rc == ERROR_SUCCESS);
1030         RegCloseKey(hKeyKeyboard);
1031     }
1032
1033     /* make sure our base layout is on the list */
1034     if (baselayout != 0)
1035     {
1036         if (nBuff && layouts)
1037         {
1038             if (count < nBuff)
1039             {
1040                 layouts[count] = (HKL)baselayout;
1041                 count++;
1042             }
1043         }
1044         else
1045             count++;
1046     }
1047
1048     return count;
1049 }
1050
1051
1052 /***********************************************************************
1053  *              RegisterHotKey (USER32.@)
1054  */
1055 BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
1056 {
1057     BOOL ret;
1058     int replaced=0;
1059
1060     TRACE_(keyboard)("(%p,%d,0x%08x,%X)\n",hwnd,id,modifiers,vk);
1061
1062     if ((hwnd == NULL || WIN_IsCurrentThread(hwnd)) &&
1063         !USER_Driver->pRegisterHotKey(hwnd, modifiers, vk))
1064         return FALSE;
1065
1066     SERVER_START_REQ( register_hotkey )
1067     {
1068         req->window = wine_server_user_handle( hwnd );
1069         req->id = id;
1070         req->flags = modifiers;
1071         req->vkey = vk;
1072         if ((ret = !wine_server_call_err( req )))
1073         {
1074             replaced = reply->replaced;
1075             modifiers = reply->flags;
1076             vk = reply->vkey;
1077         }
1078     }
1079     SERVER_END_REQ;
1080
1081     if (ret && replaced)
1082         USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1083
1084     return ret;
1085 }
1086
1087 /***********************************************************************
1088  *              UnregisterHotKey (USER32.@)
1089  */
1090 BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id)
1091 {
1092     BOOL ret;
1093     UINT modifiers, vk;
1094
1095     TRACE_(keyboard)("(%p,%d)\n",hwnd,id);
1096
1097     SERVER_START_REQ( unregister_hotkey )
1098     {
1099         req->window = wine_server_user_handle( hwnd );
1100         req->id = id;
1101         if ((ret = !wine_server_call_err( req )))
1102         {
1103             modifiers = reply->flags;
1104             vk = reply->vkey;
1105         }
1106     }
1107     SERVER_END_REQ;
1108
1109     if (ret)
1110         USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1111
1112     return ret;
1113 }
1114
1115 /***********************************************************************
1116  *              LoadKeyboardLayoutW (USER32.@)
1117  */
1118 HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID, UINT Flags)
1119 {
1120     TRACE_(keyboard)("(%s, %d)\n", debugstr_w(pwszKLID), Flags);
1121
1122     return USER_Driver->pLoadKeyboardLayout(pwszKLID, Flags);
1123 }
1124
1125 /***********************************************************************
1126  *              LoadKeyboardLayoutA (USER32.@)
1127  */
1128 HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID, UINT Flags)
1129 {
1130     HKL ret;
1131     UNICODE_STRING pwszKLIDW;
1132
1133     if (pwszKLID) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW, pwszKLID);
1134     else pwszKLIDW.Buffer = NULL;
1135
1136     ret = LoadKeyboardLayoutW(pwszKLIDW.Buffer, Flags);
1137     RtlFreeUnicodeString(&pwszKLIDW);
1138     return ret;
1139 }
1140
1141
1142 /***********************************************************************
1143  *              UnloadKeyboardLayout (USER32.@)
1144  */
1145 BOOL WINAPI UnloadKeyboardLayout(HKL hkl)
1146 {
1147     TRACE_(keyboard)("(%p)\n", hkl);
1148
1149     return USER_Driver->pUnloadKeyboardLayout(hkl);
1150 }
1151
1152 typedef struct __TRACKINGLIST {
1153     TRACKMOUSEEVENT tme;
1154     POINT pos; /* center of hover rectangle */
1155 } _TRACKINGLIST;
1156
1157 /* FIXME: move tracking stuff into a per thread data */
1158 static _TRACKINGLIST tracking_info;
1159 static UINT_PTR timer;
1160
1161 static void check_mouse_leave(HWND hwnd, int hittest)
1162 {
1163     if (tracking_info.tme.hwndTrack != hwnd)
1164     {
1165         if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1166             PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
1167         else
1168             PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
1169
1170         /* remove the TME_LEAVE flag */
1171         tracking_info.tme.dwFlags &= ~TME_LEAVE;
1172     }
1173     else
1174     {
1175         if (hittest == HTCLIENT)
1176         {
1177             if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1178             {
1179                 PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
1180                 /* remove the TME_LEAVE flag */
1181                 tracking_info.tme.dwFlags &= ~TME_LEAVE;
1182             }
1183         }
1184         else
1185         {
1186             if (!(tracking_info.tme.dwFlags & TME_NONCLIENT))
1187             {
1188                 PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
1189                 /* remove the TME_LEAVE flag */
1190                 tracking_info.tme.dwFlags &= ~TME_LEAVE;
1191             }
1192         }
1193     }
1194 }
1195
1196 static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
1197                                          DWORD dwTime)
1198 {
1199     POINT pos;
1200     INT hoverwidth = 0, hoverheight = 0, hittest;
1201
1202     TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd, uMsg, idEvent, dwTime);
1203
1204     GetCursorPos(&pos);
1205     hwnd = WINPOS_WindowFromPoint(hwnd, pos, &hittest);
1206
1207     TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1208
1209     SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
1210     SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
1211
1212     TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
1213            wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
1214            hoverwidth, hoverheight);
1215
1216     /* see if this tracking event is looking for TME_LEAVE and that the */
1217     /* mouse has left the window */
1218     if (tracking_info.tme.dwFlags & TME_LEAVE)
1219     {
1220         check_mouse_leave(hwnd, hittest);
1221     }
1222
1223     if (tracking_info.tme.hwndTrack != hwnd)
1224     {
1225         /* mouse is gone, stop tracking mouse hover */
1226         tracking_info.tme.dwFlags &= ~TME_HOVER;
1227     }
1228
1229     /* see if we are tracking hovering for this hwnd */
1230     if (tracking_info.tme.dwFlags & TME_HOVER)
1231     {
1232         /* has the cursor moved outside the rectangle centered around pos? */
1233         if ((abs(pos.x - tracking_info.pos.x) > (hoverwidth / 2)) ||
1234             (abs(pos.y - tracking_info.pos.y) > (hoverheight / 2)))
1235         {
1236             /* record this new position as the current position */
1237             tracking_info.pos = pos;
1238         }
1239         else
1240         {
1241             if (hittest == HTCLIENT)
1242             {
1243                 ScreenToClient(hwnd, &pos);
1244                 TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos));
1245
1246                 PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSEHOVER,
1247                              get_key_state(), MAKELPARAM( pos.x, pos.y ));
1248             }
1249             else
1250             {
1251                 if (tracking_info.tme.dwFlags & TME_NONCLIENT)
1252                     PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSEHOVER,
1253                                  hittest, MAKELPARAM( pos.x, pos.y ));
1254             }
1255
1256             /* stop tracking mouse hover */
1257             tracking_info.tme.dwFlags &= ~TME_HOVER;
1258         }
1259     }
1260
1261     /* stop the timer if the tracking list is empty */
1262     if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
1263     {
1264         KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1265         timer = 0;
1266         tracking_info.tme.hwndTrack = 0;
1267         tracking_info.tme.dwFlags = 0;
1268         tracking_info.tme.dwHoverTime = 0;
1269     }
1270 }
1271
1272
1273 /***********************************************************************
1274  * TrackMouseEvent [USER32]
1275  *
1276  * Requests notification of mouse events
1277  *
1278  * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
1279  * to the hwnd specified in the ptme structure.  After the event message
1280  * is posted to the hwnd, the entry in the queue is removed.
1281  *
1282  * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
1283  * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
1284  * immediately and the TME_LEAVE flag being ignored.
1285  *
1286  * PARAMS
1287  *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
1288  *
1289  * RETURNS
1290  *     Success: non-zero
1291  *     Failure: zero
1292  *
1293  */
1294
1295 BOOL WINAPI
1296 TrackMouseEvent (TRACKMOUSEEVENT *ptme)
1297 {
1298     HWND hwnd;
1299     POINT pos;
1300     DWORD hover_time;
1301     INT hittest;
1302
1303     TRACE("%x, %x, %p, %u\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
1304
1305     if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
1306         WARN("wrong TRACKMOUSEEVENT size from app\n");
1307         SetLastError(ERROR_INVALID_PARAMETER);
1308         return FALSE;
1309     }
1310
1311     /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
1312     if (ptme->dwFlags & TME_QUERY )
1313     {
1314         *ptme = tracking_info.tme;
1315         /* set cbSize in the case it's not initialized yet */
1316         ptme->cbSize = sizeof(TRACKMOUSEEVENT);
1317
1318         return TRUE; /* return here, TME_QUERY is retrieving information */
1319     }
1320
1321     if (!IsWindow(ptme->hwndTrack))
1322     {
1323         SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1324         return FALSE;
1325     }
1326
1327     hover_time = (ptme->dwFlags & TME_HOVER) ? ptme->dwHoverTime : HOVER_DEFAULT;
1328
1329     /* if HOVER_DEFAULT was specified replace this with the system's current value.
1330      * TME_LEAVE doesn't need to specify hover time so use default */
1331     if (hover_time == HOVER_DEFAULT || hover_time == 0)
1332         SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
1333
1334     GetCursorPos(&pos);
1335     hwnd = WINPOS_WindowFromPoint(ptme->hwndTrack, pos, &hittest);
1336     TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1337
1338     if (ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
1339         FIXME("Unknown flag(s) %08x\n", ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT));
1340
1341     if (ptme->dwFlags & TME_CANCEL)
1342     {
1343         if (tracking_info.tme.hwndTrack == ptme->hwndTrack)
1344         {
1345             tracking_info.tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1346
1347             /* if we aren't tracking on hover or leave remove this entry */
1348             if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
1349             {
1350                 KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1351                 timer = 0;
1352                 tracking_info.tme.hwndTrack = 0;
1353                 tracking_info.tme.dwFlags = 0;
1354                 tracking_info.tme.dwHoverTime = 0;
1355             }
1356         }
1357     } else {
1358         /* In our implementation it's possible that another window will receive a
1359          * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
1360          * called. In such a situation post the WM_MOUSELEAVE now */
1361         if (tracking_info.tme.dwFlags & TME_LEAVE && tracking_info.tme.hwndTrack != NULL)
1362             check_mouse_leave(hwnd, hittest);
1363
1364         if (timer)
1365         {
1366             KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1367             timer = 0;
1368             tracking_info.tme.hwndTrack = 0;
1369             tracking_info.tme.dwFlags = 0;
1370             tracking_info.tme.dwHoverTime = 0;
1371         }
1372
1373         if (ptme->hwndTrack == hwnd)
1374         {
1375             /* Adding new mouse event to the tracking list */
1376             tracking_info.tme = *ptme;
1377             tracking_info.tme.dwHoverTime = hover_time;
1378
1379             /* Initialize HoverInfo variables even if not hover tracking */
1380             tracking_info.pos = pos;
1381
1382             timer = SetSystemTimer(tracking_info.tme.hwndTrack, (UINT_PTR)&tracking_info.tme, hover_time, TrackMouseEventProc);
1383         }
1384     }
1385
1386     return TRUE;
1387 }
1388
1389 /***********************************************************************
1390  * GetMouseMovePointsEx [USER32]
1391  *
1392  * RETURNS
1393  *     Success: count of point set in the buffer
1394  *     Failure: -1
1395  */
1396 int WINAPI GetMouseMovePointsEx(UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPOINT ptout, int count, DWORD res) {
1397
1398     if((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > 64)) {
1399         SetLastError(ERROR_INVALID_PARAMETER);
1400         return -1;
1401     }
1402
1403     if(!ptin || (!ptout && count)) {
1404         SetLastError(ERROR_NOACCESS);
1405         return -1;
1406     }
1407
1408     FIXME("(%d %p %p %d %d) stub\n", size, ptin, ptout, count, res);
1409
1410     SetLastError(ERROR_POINT_NOT_FOUND);
1411     return -1;
1412 }