1 | /* $Id: winaccel.cpp,v 1.11 2003-04-02 12:58:02 sandervl Exp $ */
|
---|
2 | /*
|
---|
3 | * Win32 accelerator key functions for OS/2
|
---|
4 | *
|
---|
5 | * Based on Wine: (windows\input.c; loader\resource.c) (20000130)
|
---|
6 | * Copyright 1993 Bob Amstadt
|
---|
7 | * Copyright 1996 Albrecht Kleine
|
---|
8 | * Copyright 1997 David Faure
|
---|
9 | * Copyright 1998 Morten Welinder
|
---|
10 | * Copyright 1998 Ulrich Weigand
|
---|
11 | * Copyright 1993 Robert J. Amstadt
|
---|
12 | * Copyright 1995 Alexandre Julliard
|
---|
13 | *
|
---|
14 | * Project Odin Software License can be found in LICENSE.TXT
|
---|
15 | *
|
---|
16 | */
|
---|
17 | #include <os2win.h>
|
---|
18 | #include <misc.h>
|
---|
19 | #include <heapstring.h>
|
---|
20 | #include "win32wbase.h"
|
---|
21 | #include <win\winnls.h>
|
---|
22 |
|
---|
23 | #define DBG_LOCALLOG DBG_winaccel
|
---|
24 | #include "dbglocal.h"
|
---|
25 |
|
---|
26 | /**********************************************************************
|
---|
27 | * KBD_translate_accelerator
|
---|
28 | *
|
---|
29 | * FIXME: should send some WM_INITMENU or/and WM_INITMENUPOPUP -messages
|
---|
30 | */
|
---|
31 | static BOOL KBD_translate_accelerator(HWND hWnd,LPMSG msg,
|
---|
32 | BYTE fVirt,WORD key,WORD cmd)
|
---|
33 | {
|
---|
34 | BOOL sendmsg = FALSE;
|
---|
35 |
|
---|
36 | if(msg->wParam == key)
|
---|
37 | {
|
---|
38 | if (msg->message == WM_CHAR) {
|
---|
39 | if ( !(fVirt & FALT) && !(fVirt & FVIRTKEY) )
|
---|
40 | {
|
---|
41 | dprintf(("TranslateAccelerator: found accel for WM_CHAR: ('%c')\n", msg->wParam&0xff));
|
---|
42 | sendmsg=TRUE;
|
---|
43 | }
|
---|
44 | }
|
---|
45 | else
|
---|
46 | {
|
---|
47 | if(fVirt & FVIRTKEY) {
|
---|
48 | INT mask = 0;
|
---|
49 | if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT;
|
---|
50 | if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL;
|
---|
51 | if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT;
|
---|
52 |
|
---|
53 | if(mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
|
---|
54 | sendmsg=TRUE;
|
---|
55 | else dprintf(("TranslateAccelerator: but incorrect SHIFT/CTRL/ALT-state %x != %x", mask, fVirt));
|
---|
56 | }
|
---|
57 | else
|
---|
58 | {
|
---|
59 | if (!(msg->lParam & 0x01000000)) /* no special_key */
|
---|
60 | {
|
---|
61 | if ((fVirt & FALT) && (msg->lParam & 0x20000000))
|
---|
62 | { /* ^^ ALT pressed */
|
---|
63 | dprintf(("TranslateAccelerator: found accel for Alt-%c\n", msg->wParam&0xff));
|
---|
64 | sendmsg=TRUE;
|
---|
65 | }
|
---|
66 | }
|
---|
67 | }
|
---|
68 | }
|
---|
69 |
|
---|
70 | if (sendmsg) /* found an accelerator, but send a message... ? */
|
---|
71 | {
|
---|
72 | INT iSysStat,iStat,mesg=0;
|
---|
73 | HMENU hMenu;
|
---|
74 |
|
---|
75 | if (msg->message == WM_KEYUP || msg->message == WM_SYSKEYUP) {
|
---|
76 | mesg=1;
|
---|
77 | }
|
---|
78 | else
|
---|
79 | if (GetCapture())
|
---|
80 | mesg=2;
|
---|
81 | else
|
---|
82 | if (!IsWindowEnabled(hWnd))
|
---|
83 | mesg=3;
|
---|
84 | else
|
---|
85 | {
|
---|
86 | Win32BaseWindow *window;
|
---|
87 |
|
---|
88 | window = Win32BaseWindow::GetWindowFromHandle(hWnd);
|
---|
89 | if(!window) {
|
---|
90 | return FALSE; //should never happen! (already checked)
|
---|
91 | }
|
---|
92 |
|
---|
93 | hMenu = GetMenu(hWnd);
|
---|
94 |
|
---|
95 | iSysStat = (window->GetSysMenu()) ? GetMenuState(GetSubMenu(window->GetSysMenu(), 0),
|
---|
96 | cmd, MF_BYCOMMAND) : -1 ;
|
---|
97 | iStat = (hMenu) ? GetMenuState(hMenu, cmd, MF_BYCOMMAND) : -1 ;
|
---|
98 |
|
---|
99 | if (iSysStat!=-1)
|
---|
100 | {
|
---|
101 | if (iSysStat & (MF_DISABLED|MF_GRAYED))
|
---|
102 | mesg=4;
|
---|
103 | else
|
---|
104 | mesg=WM_SYSCOMMAND;
|
---|
105 | }
|
---|
106 | else
|
---|
107 | {
|
---|
108 | if (iStat!=-1)
|
---|
109 | {
|
---|
110 | if (IsIconic(hWnd)) {
|
---|
111 | mesg=5;
|
---|
112 | }
|
---|
113 | else
|
---|
114 | {
|
---|
115 | if (iStat & (MF_DISABLED|MF_GRAYED))
|
---|
116 | mesg=6;
|
---|
117 | else
|
---|
118 | mesg=WM_COMMAND;
|
---|
119 | }
|
---|
120 | }
|
---|
121 | else
|
---|
122 | mesg=WM_COMMAND;
|
---|
123 | }
|
---|
124 | RELEASE_WNDOBJ(window);
|
---|
125 | }
|
---|
126 | if ( mesg==WM_COMMAND || mesg==WM_SYSCOMMAND )
|
---|
127 | {
|
---|
128 | SendMessageA(hWnd, mesg, cmd, 0x00010000L);
|
---|
129 | }
|
---|
130 | else
|
---|
131 | {
|
---|
132 | /* some reasons for NOT sending the WM_{SYS}COMMAND message:
|
---|
133 | * #0: unknown (please report!)
|
---|
134 | * #1: for WM_KEYUP,WM_SYSKEYUP
|
---|
135 | * #2: mouse is captured
|
---|
136 | * #3: window is disabled
|
---|
137 | * #4: it's a disabled system menu option
|
---|
138 | * #5: it's a menu option, but window is iconic
|
---|
139 | * #6: it's a menu option, but disabled
|
---|
140 | */
|
---|
141 | if(mesg==0)
|
---|
142 | dprintf(("ERROR: unknown reason - please report!"));
|
---|
143 | else dprintf(("but won't send WM_{SYS}COMMAND, reason is #%d\n",mesg));
|
---|
144 |
|
---|
145 | }
|
---|
146 | return TRUE;
|
---|
147 | }
|
---|
148 | dprintf(("TranslateAccelerator: not match for %x %x %x", fVirt, key, cmd));
|
---|
149 | }
|
---|
150 | return FALSE;
|
---|
151 | }
|
---|
152 | /*****************************************************************************
|
---|
153 | * Name : int WIN32API TranslateAcceleratorA
|
---|
154 | * Purpose : Translate WM_*KEYDOWN messages to WM_COMMAND messages
|
---|
155 | * according to Accelerator table
|
---|
156 | * Parameters: HWND hwnd, HACCEL haccel, LPMSG lpmsg
|
---|
157 | * Variables :
|
---|
158 | * Result : int FALSE (no accelerator found) TRUE (accelerator found)
|
---|
159 | * Remark : if a accelerator is found it is not neccesarely executed
|
---|
160 | * depends on window stat
|
---|
161 | *
|
---|
162 | *****************************************************************************/
|
---|
163 | INT WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccel, LPMSG msg)
|
---|
164 | {
|
---|
165 | /* YES, Accel16! */
|
---|
166 | LPACCEL lpAccelTbl;
|
---|
167 | int i;
|
---|
168 |
|
---|
169 | SetLastError(ERROR_SUCCESS);
|
---|
170 | if (msg == NULL)
|
---|
171 | {
|
---|
172 | dprintf(("TranslateAcceleratorAmsg null; should hang here to be win compatible"));
|
---|
173 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
174 | return 0;
|
---|
175 | }
|
---|
176 | if (!hAccel || !(lpAccelTbl = (LPACCEL)GlobalLock(hAccel)))
|
---|
177 | {
|
---|
178 | dprintf(("TranslateAcceleratorA: invalid accel handle=%x", hAccel));
|
---|
179 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
180 | return 0;
|
---|
181 | }
|
---|
182 | if(!IsWindow(hWnd)) {
|
---|
183 | dprintf(("TranslateAccelerator, window %x not found", hWnd));
|
---|
184 | SetLastError(ERROR_INVALID_WINDOW_HANDLE);
|
---|
185 | return 0;
|
---|
186 | }
|
---|
187 | if ((msg->message != WM_KEYDOWN &&
|
---|
188 | msg->message != WM_KEYUP &&
|
---|
189 | msg->message != WM_SYSKEYDOWN &&
|
---|
190 | msg->message != WM_SYSKEYUP &&
|
---|
191 | msg->message != WM_CHAR))
|
---|
192 | {
|
---|
193 | return 0;
|
---|
194 | }
|
---|
195 |
|
---|
196 | /* TRACE_(accel)("TranslateAccelerators hAccel=%04x, hWnd=%04x,"
|
---|
197 | "msg->hwnd=%04x, msg->message=%04x, wParam=%08x, lParam=%lx\n",
|
---|
198 | hAccel,hWnd,msg->hwnd,msg->message,msg->wParam,msg->lParam); */
|
---|
199 |
|
---|
200 | i = 0;
|
---|
201 | do
|
---|
202 | {
|
---|
203 | if (KBD_translate_accelerator(hWnd,msg,lpAccelTbl[i].fVirt,
|
---|
204 | lpAccelTbl[i].key,lpAccelTbl[i].cmd))
|
---|
205 | {
|
---|
206 | return 1;
|
---|
207 | }
|
---|
208 | }
|
---|
209 | while ((lpAccelTbl[i++].fVirt & 0x80) == 0);
|
---|
210 |
|
---|
211 | // WARN_(accel)("couldn't translate accelerator key\n");
|
---|
212 | return 0;
|
---|
213 | }
|
---|
214 | /**********************************************************************
|
---|
215 | * LoadAccelerators32W [USER.177]
|
---|
216 | * The image layout seems to look like this (not 100% sure):
|
---|
217 | * 00: BYTE type type of accelerator
|
---|
218 | * 01: BYTE pad (to WORD boundary)
|
---|
219 | * 02: WORD event
|
---|
220 | * 04: WORD IDval
|
---|
221 | * 06: WORD pad (to DWORD boundary)
|
---|
222 | */
|
---|
223 | HACCEL WINAPI LoadAcceleratorsW(HINSTANCE instance,LPCWSTR lpTableName)
|
---|
224 | {
|
---|
225 | HRSRC hRsrc;
|
---|
226 | HACCEL hMem,hRetval=0;
|
---|
227 | DWORD size;
|
---|
228 |
|
---|
229 | if (!(hRsrc = FindResourceW( instance, lpTableName, RT_ACCELERATORW )))
|
---|
230 | {
|
---|
231 | dprintf(("LoadAcceleratorsW couldn't find accelerator table resource %x %x", instance, lpTableName));
|
---|
232 | return 0;
|
---|
233 | }
|
---|
234 | else {
|
---|
235 | hMem = LoadResource( instance, hRsrc );
|
---|
236 | size = SizeofResource( instance, hRsrc );
|
---|
237 | if(size >= sizeof(PE_ACCEL))
|
---|
238 | {
|
---|
239 | LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
|
---|
240 | LPACCEL accel;
|
---|
241 | int i,nrofaccells = size/sizeof(PE_ACCEL);
|
---|
242 |
|
---|
243 | hRetval = GlobalAlloc(0,sizeof(ACCEL)*nrofaccells);
|
---|
244 | accel = (LPACCEL)GlobalLock(hRetval);
|
---|
245 |
|
---|
246 | for (i=0;i<nrofaccells;i++) {
|
---|
247 | accel[i].fVirt = accel_table[i].fVirt;
|
---|
248 | accel[i].key = accel_table[i].key;
|
---|
249 | accel[i].cmd = accel_table[i].cmd;
|
---|
250 | }
|
---|
251 | accel[i-1].fVirt |= 0x80;
|
---|
252 | }
|
---|
253 | }
|
---|
254 | dprintf(("LoadAcceleratorsW returned %x %x %x\n", instance, lpTableName, hRetval));
|
---|
255 | return hRetval;
|
---|
256 | }
|
---|
257 |
|
---|
258 | HACCEL WINAPI LoadAcceleratorsA(HINSTANCE instance,LPCSTR lpTableName)
|
---|
259 | {
|
---|
260 | LPWSTR uni;
|
---|
261 | HACCEL result;
|
---|
262 | if (HIWORD(lpTableName))
|
---|
263 | uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
|
---|
264 | else
|
---|
265 | uni = (LPWSTR)lpTableName;
|
---|
266 | result = LoadAcceleratorsW(instance,uni);
|
---|
267 | if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
|
---|
268 | return result;
|
---|
269 | }
|
---|
270 |
|
---|
271 | /**********************************************************************
|
---|
272 | * CopyAcceleratorTable32A (USER32.58)
|
---|
273 | */
|
---|
274 | INT WINAPI CopyAcceleratorTableA(HACCEL src, LPACCEL dst, INT entries)
|
---|
275 | {
|
---|
276 | return CopyAcceleratorTableW(src, dst, entries);
|
---|
277 | }
|
---|
278 |
|
---|
279 | /**********************************************************************
|
---|
280 | * CopyAcceleratorTable32W (USER32.59)
|
---|
281 | *
|
---|
282 | * By mortene@pvv.org 980321
|
---|
283 | */
|
---|
284 | INT WINAPI CopyAcceleratorTableW(HACCEL src, LPACCEL dst, INT entries)
|
---|
285 | {
|
---|
286 | int i,xsize;
|
---|
287 | LPACCEL accel = (LPACCEL)GlobalLock(src);
|
---|
288 | BOOL done = FALSE;
|
---|
289 |
|
---|
290 | /* Do parameter checking to avoid the explosions and the screaming
|
---|
291 | as far as possible. */
|
---|
292 | if((dst && (entries < 1)) || (src == (HACCEL)NULL) || !accel)
|
---|
293 | {
|
---|
294 | dprintf(("CopyAcceleratorTableW: Application sent invalid parameters (%p %p %d).\n", (LPVOID)src, (LPVOID)dst, entries));
|
---|
295 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
296 | return 0;
|
---|
297 | }
|
---|
298 | xsize = GlobalSize(src)/sizeof(ACCEL);
|
---|
299 | if (xsize>entries) entries=xsize;
|
---|
300 |
|
---|
301 | i=0;
|
---|
302 | while(!done) {
|
---|
303 | /* Spit out some debugging information. */
|
---|
304 | // TRACE_(accel)("accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
|
---|
305 | // i, accel[i].fVirt, accel[i].key, accel[i].cmd);
|
---|
306 |
|
---|
307 | /* Copy data to the destination structure array (if dst == NULL,
|
---|
308 | we're just supposed to count the number of entries). */
|
---|
309 | if(dst) {
|
---|
310 | dst[i].fVirt = accel[i].fVirt;
|
---|
311 | dst[i].key = accel[i].key;
|
---|
312 | dst[i].cmd = accel[i].cmd;
|
---|
313 |
|
---|
314 | /* Check if we've reached the end of the application supplied
|
---|
315 | accelerator table. */
|
---|
316 | if(i+1 == entries) {
|
---|
317 | /* Turn off the high order bit, just in case. */
|
---|
318 | dst[i].fVirt &= 0x7f;
|
---|
319 | done = TRUE;
|
---|
320 | }
|
---|
321 | }
|
---|
322 |
|
---|
323 | /* The highest order bit seems to mark the end of the accelerator
|
---|
324 | resource table, but not always. Use GlobalSize() check too. */
|
---|
325 | if((accel[i].fVirt & 0x80) != 0) done = TRUE;
|
---|
326 |
|
---|
327 | i++;
|
---|
328 | }
|
---|
329 |
|
---|
330 | return i;
|
---|
331 | }
|
---|
332 |
|
---|
333 | /*********************************************************************
|
---|
334 | * CreateAcceleratorTable (USER32.64)
|
---|
335 | *
|
---|
336 | * By mortene@pvv.org 980321
|
---|
337 | */
|
---|
338 | HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccel, INT cEntries)
|
---|
339 | {
|
---|
340 | HACCEL hAccel;
|
---|
341 | LPACCEL accel;
|
---|
342 | int i;
|
---|
343 |
|
---|
344 | /* Do parameter checking just in case someone's trying to be
|
---|
345 | funny. */
|
---|
346 | if(cEntries < 1) {
|
---|
347 | dprintf(("CreateAcceleratorTableA: Application sent invalid parameters (%p %d).\n", lpaccel, cEntries));
|
---|
348 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
349 | return NULL;
|
---|
350 | }
|
---|
351 | dprintf(("FIXME: CreateAcceleratorTableA: should check that the accelerator descriptions are valid return NULL and SetLastError() if not"));
|
---|
352 |
|
---|
353 | /* Allocate memory and copy the table. */
|
---|
354 | hAccel = GlobalAlloc(0,cEntries*sizeof(ACCEL));
|
---|
355 |
|
---|
356 | if(!hAccel) {
|
---|
357 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
358 | return (HACCEL)NULL;
|
---|
359 | }
|
---|
360 | accel = (LPACCEL)GlobalLock(hAccel);
|
---|
361 | for (i=0;i<cEntries;i++) {
|
---|
362 | accel[i].fVirt = lpaccel[i].fVirt;
|
---|
363 | accel[i].key = lpaccel[i].key;
|
---|
364 | accel[i].cmd = lpaccel[i].cmd;
|
---|
365 | }
|
---|
366 | /* Set the end-of-table terminator. */
|
---|
367 | accel[cEntries-1].fVirt |= 0x80;
|
---|
368 |
|
---|
369 | dprintf(("CreateAcceleratorTableA %x %x returned %x\n", lpaccel, cEntries, hAccel));
|
---|
370 | return hAccel;
|
---|
371 | }
|
---|
372 |
|
---|
373 | /*********************************************************************
|
---|
374 | * CreateAcceleratorTableW (USER32.64)
|
---|
375 | *
|
---|
376 | *
|
---|
377 | */
|
---|
378 | HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccel, INT cEntries)
|
---|
379 | {
|
---|
380 | HACCEL hAccel;
|
---|
381 | LPACCEL accel;
|
---|
382 | int i;
|
---|
383 | char ckey;
|
---|
384 |
|
---|
385 | /* Do parameter checking just in case someone's trying to be
|
---|
386 | funny. */
|
---|
387 | if(cEntries < 1) {
|
---|
388 | dprintf(("CreateAcceleratorTableW: Application sent invalid parameters (%p %d).\n", lpaccel, cEntries));
|
---|
389 | SetLastError(ERROR_INVALID_PARAMETER);
|
---|
390 | return NULL;
|
---|
391 | }
|
---|
392 | dprintf(("FIXME: CreateAcceleratorTableW: should check that the accelerator descriptions are valid return NULL and SetLastError() if not"));
|
---|
393 |
|
---|
394 | /* Allocate memory and copy the table. */
|
---|
395 | hAccel = GlobalAlloc(0,cEntries*sizeof(ACCEL));
|
---|
396 |
|
---|
397 | if(!hAccel) {
|
---|
398 | SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
---|
399 | return (HACCEL)NULL;
|
---|
400 | }
|
---|
401 | accel = (LPACCEL)GlobalLock(hAccel);
|
---|
402 |
|
---|
403 | for (i=0;i<cEntries;i++) {
|
---|
404 | accel[i].fVirt = lpaccel[i].fVirt;
|
---|
405 | if( !(accel[i].fVirt & FVIRTKEY) ) {
|
---|
406 | ckey = (char) lpaccel[i].key;
|
---|
407 | MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &ckey, 1, (LPWSTR)&accel[i].key, 1);
|
---|
408 | }
|
---|
409 | else accel[i].key = lpaccel[i].key;
|
---|
410 | accel[i].cmd = lpaccel[i].cmd;
|
---|
411 | }
|
---|
412 |
|
---|
413 | /* Set the end-of-table terminator. */
|
---|
414 | accel[cEntries-1].fVirt |= 0x80;
|
---|
415 |
|
---|
416 | dprintf(("CreateAcceleratorTableW %x %x returned %x\n", lpaccel, cEntries, hAccel));
|
---|
417 | return hAccel;
|
---|
418 | }
|
---|
419 |
|
---|
420 | /******************************************************************************
|
---|
421 | * DestroyAcceleratorTable [USER32.130]
|
---|
422 | * Destroys an accelerator table
|
---|
423 | *
|
---|
424 | * NOTES
|
---|
425 | * By mortene@pvv.org 980321
|
---|
426 | *
|
---|
427 | * PARAMS
|
---|
428 | * handle [I] Handle to accelerator table
|
---|
429 | *
|
---|
430 | * RETURNS STD
|
---|
431 | */
|
---|
432 | BOOL WINAPI DestroyAcceleratorTable( HACCEL handle )
|
---|
433 | {
|
---|
434 | return GlobalFree(handle);
|
---|
435 | }
|
---|
436 |
|
---|