Release 961222
[wine] / windows / keyboard.c
1 /*
2  * Keyboard related functions
3  *
4  * Copyright 1993 Bob Amstadt
5  * Copyright 1996 Albrecht Kleine 
6  */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include "win.h"
11 #include "windows.h"
12 #include "accel.h"
13 #include "debug.h"
14
15 extern BOOL MouseButtonsStates[3];
16 extern BOOL AsyncMouseButtonsStates[3];
17 extern BYTE InputKeyStateTable[256];
18 BYTE AsyncKeyStateTable[256];
19
20 extern BYTE QueueKeyStateTable[256];
21
22 /**********************************************************************
23  *              GetKeyState                     [USER.106]
24  * An application calls the GetKeyState function in response to a
25  * keyboard-input message.  This function retrieves the state of the key
26  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 390)
27  */
28 INT GetKeyState(INT keycode)
29 {
30     INT retval;
31
32     if( keycode >= VK_LBUTTON && keycode <= VK_RBUTTON )
33         retval = MouseButtonsStates[keycode - VK_LBUTTON];
34     else
35     {
36         if (keycode >= 'a' && keycode <= 'z')
37             keycode += 'A' - 'a';
38         retval = ( (INT)(QueueKeyStateTable[keycode] & 0x80) << 8 ) |
39                    (INT)(QueueKeyStateTable[keycode] & 0x01);
40     }
41
42     dprintf_key(stddeb, "GetKeyState(%x) -> %x\n", keycode, retval);
43     return retval;
44 }
45
46 /**********************************************************************
47  *              GetKeyboardState                        [USER.222]
48  * An application calls the GetKeyboardState function in response to a
49  * keyboard-input message.  This function retrieves the state of the keyboard
50  * at the time the input message was generated.  (SDK 3.1 Vol 2. p 387)
51  */
52 void GetKeyboardState(BYTE *lpKeyState)
53 {
54     if (lpKeyState != NULL) {
55         QueueKeyStateTable[VK_LBUTTON] = MouseButtonsStates[0] >> 8;
56         QueueKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] >> 8;
57         QueueKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] >> 8;
58         memcpy(lpKeyState, QueueKeyStateTable, 256);
59     }
60 }
61
62 /**********************************************************************
63  *      SetKeyboardState            [USER.223]
64  */
65 void SetKeyboardState(BYTE *lpKeyState)
66 {
67     if (lpKeyState != NULL) {
68         memcpy(QueueKeyStateTable, lpKeyState, 256);
69         MouseButtonsStates[0] = QueueKeyStateTable[VK_LBUTTON]? 0x8000: 0;
70         MouseButtonsStates[1] = QueueKeyStateTable[VK_MBUTTON]? 0x8000: 0;
71         MouseButtonsStates[2] = QueueKeyStateTable[VK_RBUTTON]? 0x8000: 0;
72     }
73 }
74
75 /**********************************************************************
76  *            GetAsyncKeyState        (USER.249)
77  *
78  *      Determine if a key is or was pressed.  retval has high-order 
79  * bit set to 1 if currently pressed, low-order bit set to 1 if key has
80  * been pressed.
81  *
82  *      This uses the variable AsyncMouseButtonsStates and
83  * AsyncKeyStateTable (set in event.c) which have the mouse button
84  * number or key number (whichever is applicable) set to true if the
85  * mouse or key had been depressed since the last call to 
86  * GetAsyncKeyState.
87  */
88 int GetAsyncKeyState(int nKey)
89 {
90     short retval;       
91
92     switch (nKey) {
93      case VK_LBUTTON:
94         retval = AsyncMouseButtonsStates[0] | 
95         MouseButtonsStates[0]? 0x0001: 0;
96         break;
97      case VK_MBUTTON:
98         retval = AsyncMouseButtonsStates[1] |
99         MouseButtonsStates[1]? 0x0001: 0;
100         break;
101      case VK_RBUTTON:
102         retval = AsyncMouseButtonsStates[2] |
103         MouseButtonsStates[2]? 0x0001: 0;
104         break;
105      default:
106         retval = AsyncKeyStateTable[nKey] | 
107         (InputKeyStateTable[nKey] ? 0x8000 : 0);
108         break;
109     }
110
111     memset( AsyncMouseButtonsStates, 0, 3 );  /* all states to false */
112     memset( AsyncKeyStateTable, 0, 256 );
113
114     dprintf_key(stddeb, "GetAsyncKeyState(%x) -> %x\n", nKey, retval);
115     return retval;
116 }
117
118
119 /**********************************************************************
120  *                      TranslateAccelerator    [USER.178]
121  *
122  * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP  -messages
123  */
124 INT16 TranslateAccelerator(HWND hWnd, HACCEL16 hAccel, LPMSG16 msg)
125 {
126     ACCELHEADER *lpAccelTbl;
127     int         i;
128     BOOL sendmsg;
129     
130     if (hAccel == 0 || msg == NULL) return 0;
131     if (msg->message != WM_KEYDOWN &&
132         msg->message != WM_KEYUP &&
133         msg->message != WM_SYSKEYDOWN &&
134         msg->message != WM_SYSKEYUP &&
135         msg->message != WM_CHAR) return 0;
136
137     dprintf_accel(stddeb, "TranslateAccelerators hAccel=%04x, hWnd=%04x,\
138 msg->hwnd=%04x, msg->message=%04x\n", hAccel,hWnd,msg->hwnd,msg->message);
139
140     lpAccelTbl = (LPACCELHEADER)GlobalLock16(hAccel);
141     for (sendmsg= i = 0; i < lpAccelTbl->wCount; i++) 
142     {
143      if(msg->wParam == lpAccelTbl->tbl[i].wEvent) 
144      {
145       if (msg->message == WM_CHAR) 
146       {
147         if ( !(lpAccelTbl->tbl[i].type & ALT_ACCEL) && 
148              !(lpAccelTbl->tbl[i].type & VIRTKEY_ACCEL) )
149         {
150           dprintf_accel(stddeb,"found accel for WM_CHAR: ('%c')",msg->wParam&0xff);
151           sendmsg=TRUE;
152         }  
153       }
154       else
155       {
156        if(lpAccelTbl->tbl[i].type & VIRTKEY_ACCEL) 
157        {
158         INT mask = 0;
159         dprintf_accel(stddeb,"found accel for virt_key %04x (scan %04x)",
160                                msg->wParam,0xff & HIWORD(msg->lParam));                
161         if(GetKeyState(VK_SHIFT) & 0x8000) mask |= SHIFT_ACCEL;
162         if(GetKeyState(VK_CONTROL) & 0x8000) mask |= CONTROL_ACCEL;
163         if(GetKeyState(VK_MENU) & 0x8000) mask |= ALT_ACCEL;
164         if(mask == (lpAccelTbl->tbl[i].type &
165                             (SHIFT_ACCEL | CONTROL_ACCEL | ALT_ACCEL)))
166           sendmsg=TRUE;                     
167         else
168           dprintf_accel(stddeb,", but incorrect SHIFT/CTRL/ALT-state\n");
169        }
170        else
171        {
172          if (!(msg->lParam & 0x01000000))  /* no special_key */
173          {
174            if ((lpAccelTbl->tbl[i].type & ALT_ACCEL) && (msg->lParam & 0x20000000))
175            {                                                   /* ^^ ALT pressed */
176             dprintf_accel(stddeb,"found accel for Alt-%c", msg->wParam&0xff);
177             sendmsg=TRUE;           
178            } 
179          } 
180        }
181       } 
182
183       if (sendmsg)      /* found an accelerator, but send a message... ? */
184       {
185         INT16  iSysStat,iStat,mesg=0;
186         HMENU16 hSysMenu,hMenu;
187         
188         if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP)
189           mesg=1;
190         else 
191          if (GetCapture16())
192            mesg=2;
193          else
194           if (!IsWindowEnabled(hWnd))
195             mesg=3;
196           else
197           {
198             hMenu=GetMenu(hWnd);
199             hSysMenu=GetSystemMenu(hWnd,FALSE);
200             if (hSysMenu)
201               iSysStat=GetMenuState(hSysMenu,lpAccelTbl->tbl[i].wIDval,MF_BYCOMMAND);
202             else
203               iSysStat=-1;
204             if (hMenu)
205               iStat=GetMenuState(hMenu,lpAccelTbl->tbl[i].wIDval,MF_BYCOMMAND);
206             else
207               iStat=-1;
208             if (iSysStat!=-1)
209             {
210               if (iSysStat & (MF_DISABLED|MF_GRAYED))
211                 mesg=4;
212               else
213                 mesg=WM_SYSCOMMAND;
214             }
215             else
216             {
217               if (iStat!=-1)
218               {
219                 if (IsIconic(hWnd))
220                   mesg=5;
221                 else
222                 {
223                  if (iStat & (MF_DISABLED|MF_GRAYED))
224                    mesg=6;
225                  else
226                    mesg=WM_COMMAND;  
227                 }   
228               }
229               else
230                mesg=WM_COMMAND;  
231             }
232           }
233           if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
234           {
235               dprintf_accel(stddeb,", sending %s, wParam=%0x\n",
236                   mesg==WM_COMMAND ? "WM_COMMAND" : "WM_SYSCOMMAND",
237                   lpAccelTbl->tbl[i].wIDval);
238               SendMessage16(hWnd, mesg, lpAccelTbl->tbl[i].wIDval,0x00010000L);
239           }
240           else
241           {
242            /*  some reasons for NOT sending the WM_{SYS}COMMAND message: 
243             *   #0: unknown (please report!)
244             *   #1: for WM_KEYUP,WM_SYKEYUP
245             *   #2: mouse is captured
246             *   #3: window is disabled 
247             *   #4: it's a disabled system menu option
248             *   #5: it's a menu option, but window is iconic
249             *   #6: it's a menu option, but disabled
250             */
251             dprintf_accel(stddeb,", but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg);
252           }          
253           GlobalUnlock16(hAccel);
254           return 1;         
255       }
256      }
257     }
258     GlobalUnlock16(hAccel);
259     return 0;
260 }