indent with astyle v1.15.3: --style=ansi -c -s3 -S --convert-tabs
[reactos.git] / reactos / subsys / win32k / ntuser / accelerator.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /*
31 * Copyright 1993 Martin Ayotte
32 * Copyright 1994 Alexandre Julliard
33 * Copyright 1997 Morten Welinder
34 *
35 * This library is free software; you can redistribute it and/or
36 * modify it under the terms of the GNU Lesser General Public
37 * License as published by the Free Software Foundation; either
38 * version 2.1 of the License, or (at your option) any later version.
39 *
40 * This library is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43 * Lesser General Public License for more details.
44 *
45 * You should have received a copy of the GNU Lesser General Public
46 * License along with this library; if not, write to the Free Software
47 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
48 */
49
50 /* INCLUDES ******************************************************************/
51
52 #include <w32k.h>
53
54 #define NDEBUG
55 #include <debug.h>
56
57 /* FUNCTIONS *****************************************************************/
58
59 NTSTATUS FASTCALL
60 InitAcceleratorImpl(VOID)
61 {
62 return(STATUS_SUCCESS);
63 }
64
65 NTSTATUS FASTCALL
66 CleanupAcceleratorImpl(VOID)
67 {
68 return(STATUS_SUCCESS);
69 }
70
71
72 static
73 PACCELERATOR_TABLE FASTCALL UserGetAccelObject(HACCEL hAccel)
74 {
75 PACCELERATOR_TABLE Accel= UserGetObject(&gHandleTable, hAccel, otAccel);
76
77 if (Accel)
78 {
79 ASSERT(USER_BODY_TO_HEADER(Accel)->RefCount >= 0);
80 }
81 else
82 {
83 SetLastWin32Error(ERROR_INVALID_ACCEL_HANDLE);
84 }
85
86 return Accel;
87 }
88
89
90
91
92 int
93 STDCALL
94 NtUserCopyAcceleratorTable(
95 HACCEL hAccel,
96 LPACCEL Entries,
97 int EntriesCount)
98 {
99 PWINSTATION_OBJECT WindowStation;
100 PACCELERATOR_TABLE Accel;
101 NTSTATUS Status;
102 int Ret;
103 DECLARE_RETURN(int);
104
105 DPRINT("Enter NtUserCopyAcceleratorTable\n");
106 UserEnterShared();
107
108 Status = IntValidateWindowStationHandle(UserGetProcessWindowStation(),
109 UserMode,
110 0,
111 &WindowStation);
112
113 if (!NT_SUCCESS(Status))
114 {
115 SetLastNtError(STATUS_ACCESS_DENIED);
116 RETURN(0);
117 }
118
119 if (!(Accel = UserGetAccelObject(hAccel)))
120 {
121 ObDereferenceObject(WindowStation);
122 RETURN(0);
123 }
124
125 if(Entries)
126 {
127 Ret = min(EntriesCount, Accel->Count);
128 Status = MmCopyToCaller(Entries, Accel->Table, Ret * sizeof(ACCEL));
129 if (!NT_SUCCESS(Status))
130 {
131 ObDereferenceObject(WindowStation);
132 SetLastNtError(Status);
133 RETURN(0);
134 }
135 }
136 else
137 {
138 Ret = Accel->Count;
139 }
140
141 ObDereferenceObject(WindowStation);
142
143 RETURN(Ret);
144
145 CLEANUP:
146 DPRINT("Leave NtUserCopyAcceleratorTable, ret=%i\n",_ret_);
147 UserLeave();
148 END_CLEANUP;
149 }
150
151 HACCEL
152 STDCALL
153 NtUserCreateAcceleratorTable(
154 LPACCEL Entries,
155 SIZE_T EntriesCount)
156 {
157 PWINSTATION_OBJECT WindowStation;
158 PACCELERATOR_TABLE Accel;
159 NTSTATUS Status;
160 HACCEL hAccel;
161 DECLARE_RETURN(HACCEL);
162
163 DPRINT("Enter NtUserCreateAcceleratorTable(Entries %p, EntriesCount %d)\n",
164 Entries, EntriesCount);
165 UserEnterExclusive();
166
167 Status = IntValidateWindowStationHandle(UserGetProcessWindowStation(),
168 UserMode,
169 0,
170 &WindowStation);
171
172 if (!NT_SUCCESS(Status))
173 {
174 SetLastNtError(STATUS_ACCESS_DENIED);
175 RETURN( FALSE );
176 }
177
178 Accel = ObmCreateObject(&gHandleTable, (PHANDLE)&hAccel, otAccel, sizeof(ACCELERATOR_TABLE));
179
180 if (Accel == NULL)
181 {
182 ObDereferenceObject(WindowStation);
183 SetLastNtError(STATUS_NO_MEMORY);
184 RETURN( (HACCEL) 0 );
185 }
186
187 Accel->Count = EntriesCount;
188 if (Accel->Count > 0)
189 {
190 Accel->Table = ExAllocatePoolWithTag(PagedPool, EntriesCount * sizeof(ACCEL), TAG_ACCEL);
191 if (Accel->Table == NULL)
192 {
193 ObmDeleteObject(hAccel, otAccel);
194 ObDereferenceObject(WindowStation);
195 SetLastNtError(Status);
196 RETURN( (HACCEL) 0);
197 }
198
199 Status = MmCopyFromCaller(Accel->Table, Entries, EntriesCount * sizeof(ACCEL));
200 if (!NT_SUCCESS(Status))
201 {
202 ExFreePool(Accel->Table);
203 ObmDeleteObject(hAccel, otAccel);
204 ObDereferenceObject(WindowStation);
205 SetLastNtError(Status);
206 RETURN((HACCEL) 0);
207 }
208 }
209
210 ObDereferenceObject(WindowStation);
211
212 /* FIXME: Save HandleTable in a list somewhere so we can clean it up again */
213
214 RETURN(hAccel);
215
216 CLEANUP:
217 DPRINT("Leave NtUserCreateAcceleratorTable(Entries %p, EntriesCount %d) = %x\n",
218 Entries, EntriesCount,_ret_);
219 UserLeave();
220 END_CLEANUP;
221 }
222
223
224
225 BOOLEAN
226 STDCALL
227 NtUserDestroyAcceleratorTable(
228 HACCEL hAccel)
229 {
230 PWINSTATION_OBJECT WindowStation;
231 PACCELERATOR_TABLE Accel;
232 NTSTATUS Status;
233 DECLARE_RETURN(BOOLEAN);
234
235 /* FIXME: If the handle table is from a call to LoadAcceleratorTable, decrement it's
236 usage count (and return TRUE).
237 FIXME: Destroy only tables created using CreateAcceleratorTable.
238 */
239
240 DPRINT("NtUserDestroyAcceleratorTable(Table %x)\n", hAccel);
241 UserEnterExclusive();
242
243 Status = IntValidateWindowStationHandle(UserGetProcessWindowStation(),
244 UserMode,
245 0,
246 &WindowStation);
247
248 if (!NT_SUCCESS(Status))
249 {
250 SetLastNtError(STATUS_ACCESS_DENIED);
251 DPRINT1("E1\n");
252 RETURN( FALSE);
253 }
254
255 if (!(Accel = UserGetAccelObject(hAccel)))
256 {
257 ObDereferenceObject(WindowStation);
258 RETURN( FALSE);
259 }
260
261 ObmDeleteObject(hAccel, otAccel);
262
263 if (Accel->Table != NULL)
264 {
265 ExFreePool(Accel->Table);
266 }
267
268 ObDereferenceObject(WindowStation);
269
270 RETURN( TRUE);
271
272 CLEANUP:
273 DPRINT("Leave NtUserDestroyAcceleratorTable(Table %x) = %i\n", hAccel,_ret_);
274 UserLeave();
275 END_CLEANUP;
276 }
277
278 static
279 BOOLEAN FASTCALL
280 co_IntTranslateAccelerator(
281 PWINDOW_OBJECT Window,
282 UINT message,
283 WPARAM wParam,
284 LPARAM lParam,
285 BYTE fVirt,
286 WORD key,
287 WORD cmd)
288 {
289 UINT mesg = 0;
290
291 ASSERT_REFS_CO(Window);
292
293 DPRINT("IntTranslateAccelerator(hwnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x)\n",
294 Window->hSelf, message, wParam, lParam, fVirt, key, cmd);
295
296 if (wParam != key)
297 {
298 DPRINT("T0\n");
299 return FALSE;
300 }
301
302 if (message == WM_CHAR)
303 {
304 if (!(fVirt & FALT) && !(fVirt & FVIRTKEY))
305 {
306 DPRINT("found accel for WM_CHAR: ('%c')\n", wParam & 0xff);
307 goto found;
308 }
309 }
310 else
311 {
312 if ((fVirt & FVIRTKEY) > 0)
313 {
314 INT mask = 0;
315 DPRINT("found accel for virt_key %04x (scan %04x)\n",
316 wParam, 0xff & HIWORD(lParam));
317
318 DPRINT("NtUserGetKeyState(VK_SHIFT) = 0x%x\n",
319 UserGetKeyState(VK_SHIFT));
320 DPRINT("NtUserGetKeyState(VK_CONTROL) = 0x%x\n",
321 UserGetKeyState(VK_CONTROL));
322 DPRINT("NtUserGetKeyState(VK_MENU) = 0x%x\n",
323 UserGetKeyState(VK_MENU));
324
325 if (UserGetKeyState(VK_SHIFT) & 0x8000)
326 mask |= FSHIFT;
327 if (UserGetKeyState(VK_CONTROL) & 0x8000)
328 mask |= FCONTROL;
329 if (UserGetKeyState(VK_MENU) & 0x8000)
330 mask |= FALT;
331 if (mask == (fVirt & (FSHIFT | FCONTROL | FALT)))
332 goto found;
333 DPRINT("but incorrect SHIFT/CTRL/ALT-state\n");
334 }
335 else
336 {
337 if (!(lParam & 0x01000000)) /* no special_key */
338 {
339 if ((fVirt & FALT) && (lParam & 0x20000000))
340 { /* ^^ ALT pressed */
341 DPRINT("found accel for Alt-%c\n", wParam & 0xff);
342 goto found;
343 }
344 }
345 }
346 }
347
348 DPRINT("IntTranslateAccelerator(hwnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x) = FALSE\n",
349 Window->hSelf, message, wParam, lParam, fVirt, key, cmd);
350
351 return FALSE;
352
353 found:
354 if (message == WM_KEYUP || message == WM_SYSKEYUP)
355 mesg = 1;
356 else if (IntGetCaptureWindow())
357 mesg = 2;
358 else if (!IntIsWindowVisible(Window->hSelf)) /* FIXME: WINE IsWindowEnabled == IntIsWindowVisible? */
359 mesg = 3;
360 else
361 {
362 #if 0
363 HMENU hMenu, hSubMenu, hSysMenu;
364 UINT uSysStat = (UINT)-1, uStat = (UINT)-1, nPos;
365
366 hMenu = (UserGetWindowLongW(hWnd, GWL_STYLE) & WS_CHILD) ? 0 : GetMenu(hWnd);
367 hSysMenu = get_win_sys_menu(hWnd);
368
369 /* find menu item and ask application to initialize it */
370 /* 1. in the system menu */
371 hSubMenu = hSysMenu;
372 nPos = cmd;
373 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
374 {
375 co_IntSendMessage(hWnd, WM_INITMENU, (WPARAM)hSysMenu, 0L);
376 if(hSubMenu != hSysMenu)
377 {
378 nPos = MENU_FindSubMenu(&hSysMenu, hSubMenu);
379 TRACE_(accel)("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hSysMenu, hSubMenu, nPos);
380 co_IntSendMessage(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, TRUE));
381 }
382 uSysStat = GetMenuState(GetSubMenu(hSysMenu, 0), cmd, MF_BYCOMMAND);
383 }
384 else /* 2. in the window's menu */
385 {
386 hSubMenu = hMenu;
387 nPos = cmd;
388 if(MENU_FindItem(&hSubMenu, &nPos, MF_BYCOMMAND))
389 {
390 co_IntSendMessage(hWnd, WM_INITMENU, (WPARAM)hMenu, 0L);
391 if(hSubMenu != hMenu)
392 {
393 nPos = MENU_FindSubMenu(&hMenu, hSubMenu);
394 TRACE_(accel)("hMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu, hSubMenu, nPos);
395 co_IntSendMessage(hWnd, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELPARAM(nPos, FALSE));
396 }
397 uStat = GetMenuState(hMenu, cmd, MF_BYCOMMAND);
398 }
399 }
400
401 if (uSysStat != (UINT)-1)
402 {
403 if (uSysStat & (MF_DISABLED|MF_GRAYED))
404 mesg=4;
405 else
406 mesg=WM_SYSCOMMAND;
407 }
408 else
409 {
410 if (uStat != (UINT)-1)
411 {
412 if (IsIconic(hWnd))
413 mesg=5;
414 else
415 {
416 if (uStat & (MF_DISABLED|MF_GRAYED))
417 mesg=6;
418 else
419 mesg=WM_COMMAND;
420 }
421 }
422 else
423 {
424 mesg=WM_COMMAND;
425 }
426 }
427 #else
428 DPRINT1("menu search not implemented");
429 mesg = WM_COMMAND;
430 #endif
431
432 }
433
434 if (mesg == WM_COMMAND)
435 {
436 DPRINT(", sending WM_COMMAND, wParam=%0x\n", 0x10000 | cmd);
437 co_IntSendMessage(Window->hSelf, mesg, 0x10000 | cmd, 0L);
438 }
439 else if (mesg == WM_SYSCOMMAND)
440 {
441 DPRINT(", sending WM_SYSCOMMAND, wParam=%0x\n", cmd);
442 co_IntSendMessage(Window->hSelf, mesg, cmd, 0x00010000L);
443 }
444 else
445 {
446 /* some reasons for NOT sending the WM_{SYS}COMMAND message:
447 * #0: unknown (please report!)
448 * #1: for WM_KEYUP,WM_SYSKEYUP
449 * #2: mouse is captured
450 * #3: window is disabled
451 * #4: it's a disabled system menu option
452 * #5: it's a menu option, but window is iconic
453 * #6: it's a menu option, but disabled
454 */
455 DPRINT(", but won't send WM_{SYS}COMMAND, reason is #%d\n", mesg);
456 if (mesg == 0)
457 {
458 DPRINT1(" unknown reason - please report!");
459 }
460 }
461
462 DPRINT("IntTranslateAccelerator(hWnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x) = TRUE\n",
463 Window->hSelf, message, wParam, lParam, fVirt, key, cmd);
464
465 return TRUE;
466 }
467
468 int
469 STDCALL
470 NtUserTranslateAccelerator(
471 HWND hWnd,
472 HACCEL hAccel,
473 LPMSG Message)
474 {
475 PWINSTATION_OBJECT WindowStation = NULL;
476 PWINDOW_OBJECT Window = NULL;
477 PACCELERATOR_TABLE Accel = NULL;
478 NTSTATUS Status;
479 ULONG i;
480 DECLARE_RETURN(int);
481
482 DPRINT("NtUserTranslateAccelerator(hWnd %x, Table %x, Message %p)\n",
483 hWnd, hAccel, Message);
484 UserEnterShared();
485
486 if (Message == NULL)
487 {
488 SetLastNtError(STATUS_INVALID_PARAMETER);
489 RETURN( 0);
490 }
491
492 if ((Message->message != WM_KEYDOWN) &&
493 (Message->message != WM_SYSKEYDOWN) &&
494 (Message->message != WM_SYSCHAR) &&
495 (Message->message != WM_CHAR))
496 {
497 RETURN( 0);
498 }
499
500 Status = IntValidateWindowStationHandle(UserGetProcessWindowStation(),
501 UserMode,
502 0,
503 &WindowStation);
504
505 if (!NT_SUCCESS(Status))
506 {
507 SetLastNtError(STATUS_ACCESS_DENIED);
508 RETURN( 0);
509 }
510
511 if (!(Accel = UserGetAccelObject(hAccel)))
512 {
513 RETURN( 0);
514 }
515
516 UserRefObjectCo(Accel);
517
518 if (!(Window = UserGetWindowObject(hWnd)))
519 {
520 RETURN( 0);
521 }
522
523 UserRefObjectCo(Window);
524
525
526 /* FIXME: Associate AcceleratorTable with the current thread */
527
528 for (i = 0; i < Accel->Count; i++)
529 {
530 if (co_IntTranslateAccelerator(Window, Message->message, Message->wParam, Message->lParam,
531 Accel->Table[i].fVirt, Accel->Table[i].key,
532 Accel->Table[i].cmd))
533 {
534 DPRINT("NtUserTranslateAccelerator(hWnd %x, Table %x, Message %p) = %i end\n",
535 hWnd, hAccel, Message, 1);
536 RETURN( 1);
537 }
538 if (((Accel->Table[i].fVirt & 0x80) > 0))
539 {
540 break;
541 }
542 }
543
544 RETURN( 0);
545
546 CLEANUP:
547
548 if (Window)
549 UserDerefObjectCo(Window);
550 if (Accel)
551 UserDerefObjectCo(Accel);
552
553 if (WindowStation)
554 ObDereferenceObject(WindowStation);
555
556 DPRINT("NtUserTranslateAccelerator(hWnd %x, Table %x, Message %p) = %i end\n",
557 hWnd, hAccel, Message, 0);
558 UserLeave();
559 END_CLEANUP;
560 }