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