2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window accelerator
5 * FILE: win32ss/user/ntuser/accelerator.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 1993 Martin Ayotte
8 * Copyright 1994 Alexandre Julliard
9 * Copyright 1997 Morten Welinder
10 * Copyright 2011 Rafal Harabien
14 DBG_DEFAULT_CHANNEL(UserAccel
);
16 #define FVIRT_TBL_END 0x80
17 #define FVIRT_MASK 0x7F
19 /* FUNCTIONS *****************************************************************/
21 PACCELERATOR_TABLE FASTCALL
UserGetAccelObject(HACCEL hAccel
)
23 PACCELERATOR_TABLE Accel
;
27 EngSetLastError(ERROR_INVALID_ACCEL_HANDLE
);
31 Accel
= UserGetObject(gHandleTable
, hAccel
, TYPE_ACCELTABLE
);
34 EngSetLastError(ERROR_INVALID_ACCEL_HANDLE
);
44 co_IntTranslateAccelerator(
52 HMENU hMenu
, hSubMenu
;
55 ASSERT_REFS_CO(Window
);
57 hWnd
= Window
->head
.h
;
59 TRACE("IntTranslateAccelerator(hwnd %p, message %x, wParam %x, lParam %x, fVirt 0x%x, key %x, cmd %x)\n",
60 hWnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, pAccel
->fVirt
, pAccel
->key
, pAccel
->cmd
);
62 if (UserGetKeyState(VK_CONTROL
) & 0x8000) Mask
|= FCONTROL
;
63 if (UserGetKeyState(VK_MENU
) & 0x8000) Mask
|= FALT
; // FIXME: VK_LMENU (msg winetest!)
64 if (UserGetKeyState(VK_SHIFT
) & 0x8000) Mask
|= FSHIFT
;
65 TRACE("Mask 0x%x\n", Mask
);
67 if (pAccel
->fVirt
& FVIRTKEY
)
69 /* This is a virtual key. Process WM_(SYS)KEYDOWN messages. */
70 if (pMsg
->message
== WM_KEYDOWN
|| pMsg
->message
== WM_SYSKEYDOWN
)
72 /* Check virtual key and SHIFT, CTRL, LALT state */
73 if (pMsg
->wParam
== pAccel
->key
&& Mask
== (pAccel
->fVirt
& (FSHIFT
| FCONTROL
| FALT
)))
81 /* This is a char code. Process WM_(SYS)CHAR messages. */
82 if (pMsg
->message
== WM_CHAR
|| pMsg
->message
== WM_SYSCHAR
)
84 /* Check char code and LALT state only */
85 if (pMsg
->wParam
== pAccel
->key
&& (Mask
& FALT
) == (pAccel
->fVirt
& FALT
))
94 /* Don't translate this msg */
95 TRACE("IntTranslateAccelerator returns FALSE\n");
99 /* Check if accelerator is associated with menu command */
100 hMenu
= (Window
->style
& WS_CHILD
) ? 0 : (HMENU
)Window
->IDMenu
;
102 MenuObject
= UserGetMenuObject(hMenu
);
106 if ((MENU_FindItem (&MenuObject
, &nPos
, MF_BYPOSITION
)))
107 hSubMenu
= MenuObject
->head
.h
;
113 /* Check system menu now */
114 hMenu
= Window
->SystemMenu
;
115 hSubMenu
= hMenu
; /* system menu is a popup menu */
116 MenuObject
= UserGetMenuObject(hMenu
);
120 if ((MENU_FindItem (&MenuObject
, &nPos
, MF_BYPOSITION
)))
121 hSubMenu
= MenuObject
->head
.h
;
127 /* If this is a menu item, there is no capturing enabled and
128 window is not disabled, send WM_INITMENU */
129 if (hMenu
&& !IntGetCaptureWindow())
131 co_IntSendMessage(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
134 nPos
= IntFindSubMenu(&hMenu
, hSubMenu
);
135 TRACE("hSysMenu = %p, hSubMenu = %p, nPos = %u\n", hMenu
, hSubMenu
, nPos
);
136 co_IntSendMessage(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
140 /* Don't send any message if:
142 - menu item is disabled
143 - this is window menu and window is minimized */
144 if (!(Window
->style
& WS_DISABLED
) &&
145 !(hMenu
&& IntGetMenuState(hMenu
, pAccel
->cmd
, MF_BYCOMMAND
) & (MF_DISABLED
| MF_GRAYED
)) &&
146 !(hMenu
&& hMenu
== (HMENU
)Window
->IDMenu
&& (Window
->style
& WS_MINIMIZED
)))
148 /* If this is system menu item, send WM_SYSCOMMAND, otherwise send WM_COMMAND */
149 if (hMenu
&& hMenu
== Window
->SystemMenu
)
151 TRACE("Sending WM_SYSCOMMAND, wParam=%0x\n", pAccel
->cmd
);
152 co_IntSendMessage(hWnd
, WM_SYSCOMMAND
, pAccel
->cmd
, 0x00010000L
);
156 TRACE("Sending WM_COMMAND, wParam=%0x\n", 0x10000 | pAccel
->cmd
);
157 co_IntSendMessage(hWnd
, WM_COMMAND
, 0x10000 | pAccel
->cmd
, 0L);
161 TRACE("IntTranslateAccelerator returns TRUE\n");
166 /* SYSCALLS *****************************************************************/
171 NtUserCopyAcceleratorTable(
176 PACCELERATOR_TABLE Accel
;
180 TRACE("Enter NtUserCopyAcceleratorTable\n");
183 Accel
= UserGetAccelObject(hAccel
);
189 /* If Entries is NULL return table size */
192 RETURN(Accel
->Count
);
196 if (Accel
->Count
< EntriesCount
)
197 EntriesCount
= Accel
->Count
;
203 ProbeForWrite(Entries
, EntriesCount
*sizeof(Entries
[0]), 4);
205 for (Ret
= 0; Ret
< EntriesCount
; Ret
++)
207 Entries
[Ret
].fVirt
= Accel
->Table
[Ret
].fVirt
;
208 Entries
[Ret
].key
= Accel
->Table
[Ret
].key
;
209 Entries
[Ret
].cmd
= Accel
->Table
[Ret
].cmd
;
212 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
214 SetLastNtError(_SEH2_GetExceptionCode());
222 TRACE("Leave NtUserCopyAcceleratorTable, ret=%i\n", _ret_
);
229 NtUserCreateAcceleratorTable(
233 PACCELERATOR_TABLE Accel
;
236 NTSTATUS Status
= STATUS_SUCCESS
;
237 DECLARE_RETURN(HACCEL
);
240 TRACE("Enter NtUserCreateAcceleratorTable(Entries %p, EntriesCount %u)\n",
241 Entries
, EntriesCount
);
242 UserEnterExclusive();
244 if (!Entries
|| EntriesCount
<= 0)
246 SetLastNtError(STATUS_INVALID_PARAMETER
);
247 RETURN( (HACCEL
) NULL
);
250 pti
= PsGetCurrentThreadWin32Thread();
252 Accel
= UserCreateObject(gHandleTable
,
257 sizeof(ACCELERATOR_TABLE
));
261 SetLastNtError(STATUS_NO_MEMORY
);
262 RETURN( (HACCEL
) NULL
);
265 Accel
->Count
= EntriesCount
;
266 Accel
->Table
= ExAllocatePoolWithTag(PagedPool
, EntriesCount
* sizeof(ACCEL
), USERTAG_ACCEL
);
267 if (Accel
->Table
== NULL
)
269 UserDereferenceObject(Accel
);
270 UserDeleteObject(hAccel
, TYPE_ACCELTABLE
);
271 SetLastNtError(STATUS_NO_MEMORY
);
272 RETURN( (HACCEL
) NULL
);
277 ProbeForRead(Entries
, EntriesCount
* sizeof(ACCEL
), 4);
279 for (Index
= 0; Index
< EntriesCount
; Index
++)
281 Accel
->Table
[Index
].fVirt
= Entries
[Index
].fVirt
& FVIRT_MASK
;
282 if(Accel
->Table
[Index
].fVirt
& FVIRTKEY
)
284 Accel
->Table
[Index
].key
= Entries
[Index
].key
;
288 RtlMultiByteToUnicodeN(&Accel
->Table
[Index
].key
,
291 (PCSTR
)&Entries
[Index
].key
,
295 Accel
->Table
[Index
].cmd
= Entries
[Index
].cmd
;
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
300 Status
= _SEH2_GetExceptionCode();
304 if (!NT_SUCCESS(Status
))
306 ExFreePoolWithTag(Accel
->Table
, USERTAG_ACCEL
);
307 UserDereferenceObject(Accel
);
308 UserDeleteObject(hAccel
, TYPE_ACCELTABLE
);
309 SetLastNtError(Status
);
310 RETURN( (HACCEL
) NULL
);
313 /* FIXME: Save HandleTable in a list somewhere so we can clean it up again */
315 /* Release the extra reference (UserCreateObject added 2 references) */
316 UserDereferenceObject(Accel
);
321 TRACE("Leave NtUserCreateAcceleratorTable(Entries %p, EntriesCount %u) = %p\n",
322 Entries
, EntriesCount
, _ret_
);
328 UserDestroyAccelTable(PVOID Object
)
330 PACCELERATOR_TABLE Accel
= Object
;
332 if (Accel
->Table
!= NULL
)
334 ExFreePoolWithTag(Accel
->Table
, USERTAG_ACCEL
);
338 UserDeleteObject(Accel
->head
.h
, TYPE_ACCELTABLE
);
344 NtUserDestroyAcceleratorTable(
347 PACCELERATOR_TABLE Accel
;
348 DECLARE_RETURN(BOOLEAN
);
350 /* FIXME: If the handle table is from a call to LoadAcceleratorTable, decrement it's
351 usage count (and return TRUE).
352 FIXME: Destroy only tables created using CreateAcceleratorTable.
355 TRACE("NtUserDestroyAcceleratorTable(Table %p)\n", hAccel
);
356 UserEnterExclusive();
358 if (!(Accel
= UserGetAccelObject(hAccel
)))
363 UserDestroyAccelTable(Accel
);
368 TRACE("Leave NtUserDestroyAcceleratorTable(Table %p) = %u\n", hAccel
, _ret_
);
375 NtUserTranslateAccelerator(
378 LPMSG pUnsafeMessage
)
381 PACCELERATOR_TABLE Accel
= NULL
;
384 USER_REFERENCE_ENTRY AccelRef
, WindowRef
;
387 TRACE("NtUserTranslateAccelerator(hWnd %p, hAccel %p, Message %p)\n",
388 hWnd
, hAccel
, pUnsafeMessage
);
398 ProbeForRead(pUnsafeMessage
, sizeof(MSG
), 4);
399 RtlCopyMemory(&Message
, pUnsafeMessage
, sizeof(MSG
));
401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
403 SetLastNtError(_SEH2_GetExceptionCode());
404 _SEH2_YIELD(RETURN( 0));
408 if ((Message
.message
!= WM_KEYDOWN
) &&
409 (Message
.message
!= WM_SYSKEYDOWN
) &&
410 (Message
.message
!= WM_SYSCHAR
) &&
411 (Message
.message
!= WM_CHAR
))
416 Accel
= UserGetAccelObject(hAccel
);
422 UserRefObjectCo(Accel
, &AccelRef
);
424 Window
= UserGetWindowObject(hWnd
);
430 UserRefObjectCo(Window
, &WindowRef
);
432 /* FIXME: Associate AcceleratorTable with the current thread */
434 for (i
= 0; i
< Accel
->Count
; i
++)
436 if (co_IntTranslateAccelerator(Window
, &Message
, &Accel
->Table
[i
]))
441 /* Undocumented feature... */
442 if (Accel
->Table
[i
].fVirt
& FVIRT_TBL_END
)
449 if (Window
) UserDerefObjectCo(Window
);
450 if (Accel
) UserDerefObjectCo(Accel
);
452 TRACE("NtUserTranslateAccelerator returns %d\n", _ret_
);