Fixed typo in previous change.
[wine] / windows / 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  */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <assert.h>
17
18 #include "windef.h"
19 #include "winnls.h"
20 #include "winbase.h"
21 #include "wingdi.h"
22 #include "winuser.h"
23 #include "wine/winbase16.h"
24 #include "wine/winuser16.h"
25 #include "wine/keyboard16.h"
26 #include "wine/server.h"
27 #include "win.h"
28 #include "input.h"
29 #include "keyboard.h"
30 #include "mouse.h"
31 #include "message.h"
32 #include "queue.h"
33 #include "debugtools.h"
34 #include "winerror.h"
35
36 DECLARE_DEBUG_CHANNEL(key);
37 DECLARE_DEBUG_CHANNEL(keyboard);
38 DECLARE_DEBUG_CHANNEL(win);
39 DEFAULT_DEBUG_CHANNEL(event);
40
41 static BOOL InputEnabled = TRUE;
42 static BOOL SwappedButtons;
43
44 BYTE InputKeyStateTable[256];
45 BYTE AsyncKeyStateTable[256];
46
47 /* Storage for the USER-maintained mouse positions */
48 static DWORD PosX, PosY;
49
50 #define GET_KEYSTATE() \
51      ((InputKeyStateTable[SwappedButtons ? VK_RBUTTON : VK_LBUTTON] & 0x80 ? MK_LBUTTON : 0) | \
52       (InputKeyStateTable[SwappedButtons ? VK_LBUTTON : VK_RBUTTON] & 0x80 ? MK_RBUTTON : 0) | \
53       (InputKeyStateTable[VK_MBUTTON] & 0x80 ? MK_MBUTTON : 0) | \
54       (InputKeyStateTable[VK_SHIFT]   & 0x80 ? MK_SHIFT   : 0) | \
55       (InputKeyStateTable[VK_CONTROL] & 0x80 ? MK_CONTROL : 0))
56
57 typedef union
58 {
59     struct
60     {
61         unsigned long count : 16;
62         unsigned long code : 8;
63         unsigned long extended : 1;
64         unsigned long unused : 2;
65         unsigned long win_internal : 2;
66         unsigned long context : 1;
67         unsigned long previous : 1;
68         unsigned long transition : 1;
69     } lp1;
70     unsigned long lp2;
71 } KEYLP;
72
73
74 /***********************************************************************
75  *           queue_raw_hardware_message
76  *
77  * Add a message to the raw hardware queue.
78  * Note: the position is relative to the desktop window.
79  */
80 static void queue_raw_hardware_message( UINT message, WPARAM wParam, LPARAM lParam,
81                                         int xPos, int yPos, DWORD time, DWORD extraInfo )
82 {
83     SERVER_START_REQ( send_message )
84     {
85         req->id     = (void *)GetCurrentThreadId();
86         req->type   = MSG_HARDWARE_RAW;
87         req->win    = 0;
88         req->msg    = message;
89         req->wparam = wParam;
90         req->lparam = lParam;
91         req->x      = xPos;
92         req->y      = yPos;
93         req->time   = time;
94         req->info   = extraInfo;
95         req->timeout = 0;
96         SERVER_CALL();
97     }
98     SERVER_END_REQ;
99 }
100
101
102 /***********************************************************************
103  *           queue_kbd_event
104  *
105  * Put a keyboard event into a thread queue
106  */
107 static void queue_kbd_event( const KEYBDINPUT *ki )
108 {
109     UINT message;
110     KEYLP keylp;
111
112     keylp.lp2 = 0;
113     keylp.lp1.count = 1;
114     keylp.lp1.code = ki->wScan;
115     keylp.lp1.extended = (ki->dwFlags & KEYEVENTF_EXTENDEDKEY) != 0;
116     keylp.lp1.win_internal = 0; /* this has something to do with dialogs,
117                                 * don't remember where I read it - AK */
118                                 /* it's '1' under windows, when a dialog box appears
119                                  * and you press one of the underlined keys - DF*/
120
121     if (ki->dwFlags & KEYEVENTF_KEYUP )
122     {
123         BOOL sysKey = (InputKeyStateTable[VK_MENU] & 0x80) &&
124                       !(InputKeyStateTable[VK_CONTROL] & 0x80);
125         InputKeyStateTable[ki->wVk] &= ~0x80;
126         keylp.lp1.previous = 1;
127         keylp.lp1.transition = 1;
128         message = sysKey ? WM_SYSKEYUP : WM_KEYUP;
129     }
130     else
131     {
132         keylp.lp1.previous = (InputKeyStateTable[ki->wVk] & 0x80) != 0;
133         keylp.lp1.transition = 0;
134         if (!(InputKeyStateTable[ki->wVk] & 0x80)) InputKeyStateTable[ki->wVk] ^= 0x01;
135         InputKeyStateTable[ki->wVk] |= 0x80;
136         AsyncKeyStateTable[ki->wVk] |= 0x80;
137
138         message = (InputKeyStateTable[VK_MENU] & 0x80) && !(InputKeyStateTable[VK_CONTROL] & 0x80)
139               ? WM_SYSKEYDOWN : WM_KEYDOWN;
140     }
141
142     if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP )
143         keylp.lp1.context = (InputKeyStateTable[VK_MENU] & 0x80) != 0; /* 1 if alt */
144
145     TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n",
146                 ki->wVk, keylp.lp2, InputKeyStateTable[ki->wVk] );
147
148     queue_raw_hardware_message( message, ki->wVk, keylp.lp2,
149                                 PosX, PosY, ki->time, ki->dwExtraInfo );
150 }
151
152
153 /***********************************************************************
154  *              queue_mouse_event
155  */
156 static void queue_mouse_event( const MOUSEINPUT *mi, WORD keystate )
157 {
158     if (mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
159     {
160         PosX = (mi->dx * GetSystemMetrics(SM_CXSCREEN)) >> 16;
161         PosY = (mi->dy * GetSystemMetrics(SM_CYSCREEN)) >> 16;
162     }
163     else if (mi->dwFlags & MOUSEEVENTF_MOVE)
164     {
165         int width  = GetSystemMetrics(SM_CXSCREEN);
166         int height = GetSystemMetrics(SM_CYSCREEN);
167         long posX = (long) PosX, posY = (long) PosY;
168
169         /* dx and dy can be negative numbers for relative movements */
170         posX += (long)mi->dx;
171         posY += (long)mi->dy;
172
173         /* Clip to the current screen size */
174         if (posX < 0) PosX = 0;
175         else if (posX >= width) PosX = width - 1;
176         else PosX = posX;
177
178         if (posY < 0) PosY = 0;
179         else if (posY >= height) PosY = height - 1;
180         else PosY = posY;
181     }
182
183     if (mi->dwFlags & MOUSEEVENTF_MOVE)
184     {
185         queue_raw_hardware_message( WM_MOUSEMOVE, keystate, 0, PosX, PosY,
186                                     mi->time, mi->dwExtraInfo );
187     }
188     if (mi->dwFlags & (!SwappedButtons? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN))
189     {
190         InputKeyStateTable[VK_LBUTTON] |= 0x80;
191         AsyncKeyStateTable[VK_LBUTTON] |= 0x80;
192         queue_raw_hardware_message( WM_LBUTTONDOWN, keystate, 0, PosX, PosY,
193                                     mi->time, mi->dwExtraInfo );
194     }
195     if (mi->dwFlags & (!SwappedButtons? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP))
196     {
197         AsyncKeyStateTable[VK_LBUTTON] &= ~0x80;
198         queue_raw_hardware_message( WM_LBUTTONUP, keystate, 0, PosX, PosY,
199                                     mi->time, mi->dwExtraInfo );
200     }
201     if (mi->dwFlags & (!SwappedButtons? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN))
202     {
203         InputKeyStateTable[VK_RBUTTON] |= 0x80;
204         AsyncKeyStateTable[VK_RBUTTON] |= 0x80;
205         queue_raw_hardware_message( WM_RBUTTONDOWN, keystate, 0, PosX, PosY,
206                                     mi->time, mi->dwExtraInfo );
207     }
208     if (mi->dwFlags & (!SwappedButtons? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP))
209     {
210         AsyncKeyStateTable[VK_RBUTTON] &= ~0x80;
211         queue_raw_hardware_message( WM_RBUTTONUP, keystate, 0, PosX, PosY,
212                                     mi->time, mi->dwExtraInfo );
213     }
214     if (mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
215     {
216         InputKeyStateTable[VK_MBUTTON] |= 0x80;
217         AsyncKeyStateTable[VK_MBUTTON] |= 0x80;
218         queue_raw_hardware_message( WM_MBUTTONDOWN, keystate, 0, PosX, PosY,
219                                     mi->time, mi->dwExtraInfo );
220     }
221     if (mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
222     {
223         AsyncKeyStateTable[VK_MBUTTON] &= ~0x80;
224         queue_raw_hardware_message( WM_MBUTTONUP, keystate, 0, PosX, PosY,
225                                     mi->time, mi->dwExtraInfo );
226     }
227     if (mi->dwFlags & MOUSEEVENTF_WHEEL)
228     {
229         queue_raw_hardware_message( WM_MOUSEWHEEL, MAKELONG( keystate, mi->mouseData), 0,
230                                     PosX, PosY, mi->time, mi->dwExtraInfo );
231     }
232 }
233
234
235 /***********************************************************************
236  *              SendInput  (USER32.@)
237  */
238 UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
239 {
240     UINT i;
241
242     if (!InputEnabled) return 0;
243
244     for (i = 0; i < count; i++, inputs++)
245     {
246         switch(inputs->type)
247         {
248         case INPUT_MOUSE:
249             queue_mouse_event( &inputs->u.mi, GET_KEYSTATE() );
250             break;
251         case INPUT_KEYBOARD:
252             queue_kbd_event( &inputs->u.ki );
253             break;
254         case INPUT_HARDWARE:
255             FIXME( "INPUT_HARDWARE not supported\n" );
256             break;
257         }
258     }
259     return count;
260 }
261
262
263 /***********************************************************************
264  *              keybd_event (USER32.@)
265  */
266 void WINAPI keybd_event( BYTE bVk, BYTE bScan,
267                          DWORD dwFlags, DWORD dwExtraInfo )
268 {
269     INPUT input;
270
271     /*
272      * If we are called by the Wine keyboard driver, use the additional
273      * info pointed to by the dwExtraInfo argument.
274      * Otherwise, we need to determine that info ourselves (probably
275      * less accurate, but we can't help that ...).
276      */
277     if (   !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_KEYBDEVENT) )
278         && ((WINE_KEYBDEVENT *)dwExtraInfo)->magic == WINE_KEYBDEVENT_MAGIC )
279     {
280         WINE_KEYBDEVENT *wke = (WINE_KEYBDEVENT *)dwExtraInfo;
281         input.u.ki.time = wke->time;
282         input.u.ki.dwExtraInfo = 0;
283     }
284     else
285     {
286         input.u.ki.time = GetTickCount();
287         input.u.ki.dwExtraInfo = dwExtraInfo;
288     }
289     input.type = INPUT_KEYBOARD;
290     input.u.ki.wVk = bVk;
291     input.u.ki.wScan = bScan;
292     input.u.ki.dwFlags = dwFlags;
293     SendInput( 1, &input, sizeof(input) );
294 }
295
296
297 /***********************************************************************
298  *              keybd_event (USER.289)
299  */
300 void WINAPI keybd_event16( CONTEXT86 *context )
301 {
302     DWORD dwFlags = 0;
303
304     if (AH_reg(context) & 0x80) dwFlags |= KEYEVENTF_KEYUP;
305     if (BH_reg(context) & 1   ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
306
307     keybd_event( AL_reg(context), BL_reg(context),
308                  dwFlags, MAKELONG(SI_reg(context), DI_reg(context)) );
309 }
310
311
312 /***********************************************************************
313  *              mouse_event (USER32.@)
314  */
315 void WINAPI mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
316                          DWORD dwData, DWORD dwExtraInfo )
317 {
318     INPUT input;
319     WORD keyState;
320
321     input.type = INPUT_MOUSE;
322     input.u.mi.dx = dx;
323     input.u.mi.dy = dy;
324     input.u.mi.mouseData = dwData;
325     input.u.mi.dwFlags = dwFlags;
326
327     /*
328      * If we are called by the Wine mouse driver, use the additional
329      * info pointed to by the dwExtraInfo argument.
330      * Otherwise, we need to determine that info ourselves (probably
331      * less accurate, but we can't help that ...).
332      */
333     if (dwExtraInfo && !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
334         && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC )
335     {
336         WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
337
338         keyState = wme->keyState;
339
340         if (keyState != GET_KEYSTATE())
341         {
342             /* We need to update the keystate with what X provides us */
343             InputKeyStateTable[SwappedButtons ? VK_RBUTTON : VK_LBUTTON] = (keyState & MK_LBUTTON ? 0x80 : 0);
344             InputKeyStateTable[SwappedButtons ? VK_LBUTTON : VK_RBUTTON] = (keyState & MK_RBUTTON ? 0x80 : 0);
345             InputKeyStateTable[VK_MBUTTON]             = (keyState & MK_MBUTTON ? 0x80 : 0);
346             InputKeyStateTable[VK_SHIFT]               = (keyState & MK_SHIFT   ? 0x80 : 0);
347             InputKeyStateTable[VK_CONTROL]             = (keyState & MK_CONTROL ? 0x80 : 0);
348         }
349         input.u.mi.time = wme->time;
350         input.u.mi.dwExtraInfo = (ULONG_PTR)wme->hWnd;
351         queue_mouse_event( &input.u.mi, keyState );
352     }
353     else
354     {
355         if ( dwFlags & MOUSEEVENTF_MOVE ) /* we have to actually move the cursor */
356             SetCursorPos( PosX, PosY );
357
358         input.u.mi.time = GetCurrentTime();
359         input.u.mi.dwExtraInfo = dwExtraInfo;
360         SendInput( 1, &input, sizeof(input) );
361     }
362 }
363
364
365 /***********************************************************************
366  *              mouse_event (USER.299)
367  */
368 void WINAPI mouse_event16( CONTEXT86 *context )
369 {
370     mouse_event( AX_reg(context), BX_reg(context), CX_reg(context),
371                  DX_reg(context), MAKELONG(SI_reg(context), DI_reg(context)) );
372 }
373
374 /***********************************************************************
375  *              GetMouseEventProc (USER.337)
376  */
377 FARPROC16 WINAPI GetMouseEventProc16(void)
378 {
379     HMODULE16 hmodule = GetModuleHandle16("USER");
380     return GetProcAddress16( hmodule, "mouse_event" );
381 }
382
383
384 /**********************************************************************
385  *              EnableHardwareInput (USER.331)
386  */
387 BOOL16 WINAPI EnableHardwareInput16(BOOL16 bEnable)
388 {
389   BOOL16 bOldState = InputEnabled;
390   FIXME_(event)("(%d) - stub\n", bEnable);
391   InputEnabled = bEnable;
392   return bOldState;
393 }
394
395
396 /***********************************************************************
397  *              SwapMouseButton (USER.186)
398  */
399 BOOL16 WINAPI SwapMouseButton16( BOOL16 fSwap )
400 {
401     BOOL16 ret = SwappedButtons;
402     SwappedButtons = fSwap;
403     return ret;
404 }
405
406
407 /***********************************************************************
408  *              SwapMouseButton (USER32.@)
409  */
410 BOOL WINAPI SwapMouseButton( BOOL fSwap )
411 {
412     BOOL ret = SwappedButtons;
413     SwappedButtons = fSwap;
414     return ret;
415 }
416
417
418 /***********************************************************************
419  *              GetCursorPos (USER.17)
420  */
421 BOOL16 WINAPI GetCursorPos16( POINT16 *pt )
422 {
423     POINT pos;
424     if (!pt) return 0;
425     GetCursorPos(&pos);
426     pt->x = pos.x;
427     pt->y = pos.y;
428     return 1;
429 }
430
431
432 /***********************************************************************
433  *              GetCursorPos (USER32.@)
434  */
435 BOOL WINAPI GetCursorPos( POINT *pt )
436 {
437     if (!pt) return 0;
438     pt->x = PosX;
439     pt->y = PosY;
440     if (USER_Driver.pGetCursorPos) USER_Driver.pGetCursorPos( pt );
441     return 1;
442 }
443
444
445 /***********************************************************************
446  *              SetCursorPos (USER.70)
447  */
448 void WINAPI SetCursorPos16( INT16 x, INT16 y )
449 {
450     SetCursorPos( x, y );
451 }
452
453
454 /***********************************************************************
455  *              SetCursorPos (USER32.@)
456  */
457 BOOL WINAPI SetCursorPos( INT x, INT y )
458 {
459     if (USER_Driver.pSetCursorPos) USER_Driver.pSetCursorPos( x, y );
460     PosX = x;
461     PosY = y;
462     return TRUE;
463 }
464
465
466 /**********************************************************************
467  *              EVENT_Capture
468  *
469  * We need this to be able to generate double click messages
470  * when menu code captures mouse in the window without CS_DBLCLK style.
471  */
472 HWND EVENT_Capture(HWND hwnd, INT16 ht)
473 {
474     HWND capturePrev = 0, captureWnd = 0;
475     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
476     WND* wndPtr = 0;
477     INT16 captureHT = 0;
478
479     capturePrev = GetCapture();
480
481     if (!hwnd)
482     {
483         captureWnd = 0;
484         captureHT = 0;
485     }
486     else
487     {
488         wndPtr = WIN_FindWndPtr( hwnd );
489         if (wndPtr)
490         {
491             TRACE_(win)("(0x%04x)\n", hwnd );
492             captureWnd   = wndPtr->hwndSelf;
493             captureHT    = ht;
494         }
495     }
496
497     /* Get the messageQ for the current thread */
498     if (!(pCurMsgQ = QUEUE_Current()))
499     {
500         WARN_(win)("\tCurrent message queue not found. Exiting!\n" );
501         goto CLEANUP;
502     }
503
504     /* Update the perQ capture window and send messages */
505     if( capturePrev != captureWnd )
506     {
507         if (wndPtr)
508         {
509             /* Retrieve the message queue associated with this window */
510             pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
511             if ( !pMsgQ )
512             {
513                 WARN_(win)("\tMessage queue not found. Exiting!\n" );
514                 goto CLEANUP;
515             }
516
517             /* Make sure that message queue for the window we are setting capture to
518              * shares the same perQ data as the current threads message queue.
519              */
520             if ( pCurMsgQ->pQData != pMsgQ->pQData )
521                 goto CLEANUP;
522         }
523
524         PERQDATA_SetCaptureWnd( captureWnd, captureHT );
525         if (capturePrev) SendMessageA( capturePrev, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
526     }
527
528 CLEANUP:
529     /* Unlock the queues before returning */
530     if ( pMsgQ )
531         QUEUE_Unlock( pMsgQ );
532
533     WIN_ReleaseWndPtr(wndPtr);
534     return capturePrev;
535 }
536
537
538 /**********************************************************************
539  *              SetCapture (USER32.@)
540  */
541 HWND WINAPI SetCapture( HWND hwnd )
542 {
543     return EVENT_Capture( hwnd, HTCLIENT );
544 }
545
546
547 /**********************************************************************
548  *              ReleaseCapture (USER32.@)
549  */
550 BOOL WINAPI ReleaseCapture(void)
551 {
552     return (EVENT_Capture( 0, 0 ) != 0);
553 }
554
555
556 /**********************************************************************
557  *              GetCapture (USER32.@)
558  */
559 HWND WINAPI GetCapture(void)
560 {
561     INT hittest;
562     return PERQDATA_GetCaptureWnd( &hittest );
563 }
564
565 /**********************************************************************
566  *              GetAsyncKeyState (USER32.@)
567  *
568  *      Determine if a key is or was pressed.  retval has high-order 
569  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
570  * been pressed.
571  *
572  *      This uses the variable AsyncMouseButtonsStates and
573  * AsyncKeyStateTable (set in event.c) which have the mouse button
574  * number or key number (whichever is applicable) set to true if the
575  * mouse or key had been depressed since the last call to 
576  * GetAsyncKeyState.
577  */
578 WORD WINAPI GetAsyncKeyState(INT nKey)
579 {
580     WORD retval = ((AsyncKeyStateTable[nKey] & 0x80) ? 0x0001 : 0) |
581                   ((InputKeyStateTable[nKey] & 0x80) ? 0x8000 : 0);
582     AsyncKeyStateTable[nKey] = 0;
583     TRACE_(key)("(%x) -> %x\n", nKey, retval);
584     return retval;
585 }
586
587 /**********************************************************************
588  *              GetAsyncKeyState (USER.249)
589  */
590 WORD WINAPI GetAsyncKeyState16(INT16 nKey)
591 {
592     return GetAsyncKeyState(nKey);
593 }
594
595 /***********************************************************************
596  *              IsUserIdle (USER.333)
597  */
598 BOOL16 WINAPI IsUserIdle16(void)
599 {
600     if ( GetAsyncKeyState( VK_LBUTTON ) & 0x8000 )
601         return FALSE;
602
603     if ( GetAsyncKeyState( VK_RBUTTON ) & 0x8000 )
604         return FALSE;
605
606     if ( GetAsyncKeyState( VK_MBUTTON ) & 0x8000 )
607         return FALSE;
608
609     /* Should check for screen saver activation here ... */
610
611     return TRUE;
612 }
613
614 /**********************************************************************
615  *              VkKeyScanA (USER32.@)
616  */
617 WORD WINAPI VkKeyScanA(CHAR cChar)
618 {
619         return VkKeyScan16(cChar);
620 }
621
622 /******************************************************************************
623  *              VkKeyScanW (USER32.@)
624  */
625 WORD WINAPI VkKeyScanW(WCHAR cChar)
626 {
627         return VkKeyScanA((CHAR)cChar); /* FIXME: check unicode */
628 }
629
630 /**********************************************************************
631  *              VkKeyScanExA (USER32.@)
632  */
633 WORD WINAPI VkKeyScanExA(CHAR cChar, HKL dwhkl)
634 {
635                                 /* FIXME: complete workaround this is */
636                                 return VkKeyScan16(cChar);
637 }
638
639 /******************************************************************************
640  *              VkKeyScanExW (USER32.@)
641  */
642 WORD WINAPI VkKeyScanExW(WCHAR cChar, HKL dwhkl)
643 {
644                                 /* FIXME: complete workaround this is */
645                                 return VkKeyScanA((CHAR)cChar); /* FIXME: check unicode */
646 }
647  
648 /******************************************************************************
649  *              GetKeyboardType (USER32.@)
650  */
651 INT WINAPI GetKeyboardType(INT nTypeFlag)
652 {
653   return GetKeyboardType16(nTypeFlag);
654 }
655
656 /******************************************************************************
657  *              MapVirtualKeyA (USER32.@)
658  */
659 UINT WINAPI MapVirtualKeyA(UINT code, UINT maptype)
660 {
661     return MapVirtualKey16(code,maptype);
662 }
663
664 /******************************************************************************
665  *              MapVirtualKeyW (USER32.@)
666  */
667 UINT WINAPI MapVirtualKeyW(UINT code, UINT maptype)
668 {
669     return MapVirtualKey16(code,maptype);
670 }
671
672 /******************************************************************************
673  *              MapVirtualKeyExA (USER32.@)
674  */
675 UINT WINAPI MapVirtualKeyExA(UINT code, UINT maptype, HKL hkl)
676 {
677     if (hkl)
678         FIXME_(keyboard)("(%d,%d,0x%08lx), hkl unhandled!\n",code,maptype,(DWORD)hkl);
679     return MapVirtualKey16(code,maptype);
680 }
681
682 /******************************************************************************
683  *              MapVirtualKeyExW (USER32.@)
684  */
685 UINT WINAPI MapVirtualKeyExW(UINT code, UINT maptype, HKL hkl)
686 {
687     if (hkl)
688         FIXME_(keyboard)("(%d,%d,0x%08lx), hkl unhandled!\n",code,maptype,(DWORD)hkl);
689     return MapVirtualKey16(code,maptype);
690 }
691
692 /****************************************************************************
693  *              GetKBCodePage (USER32.@)
694  */
695 UINT WINAPI GetKBCodePage(void)
696 {
697     return GetOEMCP();
698 }
699
700 /****************************************************************************
701  *              GetKeyboardLayoutName (USER.477)
702  */
703 INT16 WINAPI GetKeyboardLayoutName16(LPSTR pwszKLID)
704 {
705         return GetKeyboardLayoutNameA(pwszKLID);
706 }
707
708 /***********************************************************************
709  *              GetKeyboardLayout (USER32.@)
710  *
711  * FIXME: - device handle for keyboard layout defaulted to 
712  *          the language id. This is the way Windows default works.
713  *        - the thread identifier (dwLayout) is also ignored.
714  */
715 HKL WINAPI GetKeyboardLayout(DWORD dwLayout)
716 {
717         HKL layout;
718         layout = GetSystemDefaultLCID(); /* FIXME */
719         layout |= (layout<<16);          /* FIXME */
720         TRACE_(keyboard)("returning %08x\n",layout);
721         return layout;
722 }
723
724 /****************************************************************************
725  *              GetKeyboardLayoutNameA (USER32.@)
726  */
727 INT WINAPI GetKeyboardLayoutNameA(LPSTR pwszKLID)
728 {
729         sprintf(pwszKLID, "%08x",GetKeyboardLayout(0));
730         return 1;
731 }
732
733 /****************************************************************************
734  *              GetKeyboardLayoutNameW (USER32.@)
735  */
736 INT WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID)
737 {
738         char buf[KL_NAMELENGTH];
739         int res = GetKeyboardLayoutNameA(buf);
740         MultiByteToWideChar( CP_ACP, 0, buf, -1, pwszKLID, KL_NAMELENGTH );
741         return res;
742 }
743
744 /****************************************************************************
745  *              GetKeyNameTextA (USER32.@)
746  */
747 INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize)
748 {
749         return GetKeyNameText16(lParam,lpBuffer,nSize);
750 }
751
752 /****************************************************************************
753  *              GetKeyNameTextW (USER32.@)
754  */
755 INT WINAPI GetKeyNameTextW(LONG lParam, LPWSTR lpBuffer, INT nSize)
756 {
757         int res;
758         LPSTR buf = HeapAlloc( GetProcessHeap(), 0, nSize );
759         if(buf == NULL) return 0; /* FIXME: is this the correct failure value?*/
760         res = GetKeyNameTextA(lParam,buf,nSize);
761
762         if (nSize > 0 && !MultiByteToWideChar( CP_ACP, 0, buf, -1, lpBuffer, nSize ))
763             lpBuffer[nSize-1] = 0;
764         HeapFree( GetProcessHeap(), 0, buf );
765         return res;
766 }
767
768 /****************************************************************************
769  *              ToUnicode (USER32.@)
770  */
771 INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
772                      LPWSTR lpwStr, int size, UINT flags)
773 {
774     return USER_Driver.pToUnicode(virtKey, scanCode, lpKeyState, lpwStr, size, flags);
775 }
776
777 /****************************************************************************
778  *              ToUnicodeEx (USER32.@)
779  */
780 INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
781                        LPWSTR lpwStr, int size, UINT flags, HKL hkl)
782 {
783     /* FIXME: need true implementation */
784     return ToUnicode(virtKey, scanCode, lpKeyState, lpwStr, size, flags);
785 }
786
787 /****************************************************************************
788  *              ToAscii (USER32.@)
789  */
790 INT WINAPI ToAscii( UINT virtKey,UINT scanCode,LPBYTE lpKeyState,
791                         LPWORD lpChar,UINT flags )
792 {
793     WCHAR uni_chars[2];
794     INT ret, n_ret;
795
796     ret = ToUnicode(virtKey, scanCode, lpKeyState, uni_chars, 2, flags);
797     if(ret < 0) n_ret = 1; /* FIXME: make ToUnicode return 2 for dead chars */
798     else n_ret = ret;
799     WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL);
800     return ret;
801 }
802
803 /****************************************************************************
804  *              ToAsciiEx (USER32.@)
805  */
806 INT WINAPI ToAsciiEx( UINT virtKey, UINT scanCode, LPBYTE lpKeyState,
807                       LPWORD lpChar, UINT flags, HKL dwhkl )
808 {
809     /* FIXME: need true implementation */
810     return ToAscii(virtKey, scanCode, lpKeyState, lpChar, flags);
811 }
812
813 /**********************************************************************
814  *              ActivateKeyboardLayout (USER32.@)
815  *
816  * Call ignored. WINE supports only system default keyboard layout.
817  */
818 HKL WINAPI ActivateKeyboardLayout(HKL hLayout, UINT flags)
819 {
820     TRACE_(keyboard)("(%d, %d)\n", hLayout, flags);
821     ERR_(keyboard)("Only default system keyboard layout supported. Call ignored.\n");
822     return 0;
823 }
824
825
826 /***********************************************************************
827  *              GetKeyboardLayoutList (USER32.@)
828  *
829  * FIXME: Supports only the system default language and layout and 
830  *          returns only 1 value.
831  *
832  * Return number of values available if either input parm is 
833  *  0, per MS documentation.
834  *
835  */
836 INT WINAPI GetKeyboardLayoutList(INT nBuff,HKL *layouts)
837 {
838         TRACE_(keyboard)("(%d,%p)\n",nBuff,layouts);
839         if (!nBuff || !layouts)
840             return 1;
841         if (layouts)
842                 layouts[0] = GetKeyboardLayout(0);
843         return 1;
844 }
845
846
847 /***********************************************************************
848  *              RegisterHotKey (USER32.@)
849  */
850 BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk) {
851         FIXME_(keyboard)("(0x%08x,%d,0x%08x,%d): stub\n",hwnd,id,modifiers,vk);
852         return TRUE;
853 }
854
855 /***********************************************************************
856  *              UnregisterHotKey (USER32.@)
857  */
858 BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id) {
859         FIXME_(keyboard)("(0x%08x,%d): stub\n",hwnd,id);
860         return TRUE;
861 }
862
863 /***********************************************************************
864  *              LoadKeyboardLayoutA (USER32.@)
865  * Call ignored. WINE supports only system default keyboard layout.
866  */
867 HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID, UINT Flags)
868 {
869     TRACE_(keyboard)("(%s, %d)\n", pwszKLID, Flags);
870     ERR_(keyboard)("Only default system keyboard layout supported. Call ignored.\n");
871   return 0; 
872 }
873
874 /***********************************************************************
875  *              LoadKeyboardLayoutW (USER32.@)
876  */
877 HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID, UINT Flags)
878 {
879     char buf[9];
880     
881     WideCharToMultiByte( CP_ACP, 0, pwszKLID, -1, buf, sizeof(buf), NULL, NULL );
882     buf[8] = 0;
883     return LoadKeyboardLayoutA(buf, Flags);
884 }