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