2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window accelerator
5 * FILE: subsystems/win32/win32k/ntuser/accelerator.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
12 * Copyright 1993 Martin Ayotte
13 * Copyright 1994 Alexandre Julliard
14 * Copyright 1997 Morten Welinder
15 * Copyright 2011 Rafal Harabien
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
32 /* INCLUDES ******************************************************************/
36 #define FVIRT_TBL_END 0x80
37 #define FVIRT_MASK 0x7F
39 DBG_DEFAULT_CHANNEL(UserAccel
);
41 /* FUNCTIONS *****************************************************************/
43 PACCELERATOR_TABLE FASTCALL
UserGetAccelObject(HACCEL hAccel
)
45 PACCELERATOR_TABLE Accel
;
49 EngSetLastError(ERROR_INVALID_ACCEL_HANDLE
);
53 Accel
= UserGetObject(gHandleTable
, hAccel
, otAccel
);
56 EngSetLastError(ERROR_INVALID_ACCEL_HANDLE
);
66 co_IntTranslateAccelerator(
74 HMENU hMenu
, hSubMenu
;
75 PMENU_OBJECT MenuObject
, SubMenu
;
78 ASSERT_REFS_CO(Window
);
80 hWnd
= Window
->head
.h
;
82 TRACE("IntTranslateAccelerator(hwnd %x, message %x, wParam %x, lParam %x, fVirt %d, key %x, cmd %x)\n",
83 hWnd
, pMsg
->message
, pMsg
->wParam
, pMsg
->lParam
, pAccel
->fVirt
, pAccel
->key
, pAccel
->cmd
);
85 if (UserGetKeyState(VK_CONTROL
) & 0x8000) Mask
|= FCONTROL
;
86 if (UserGetKeyState(VK_MENU
) & 0x8000) Mask
|= FALT
; // FIXME: VK_LMENU (msg winetest!)
87 if (UserGetKeyState(VK_SHIFT
) & 0x8000) Mask
|= FSHIFT
;
88 TRACE("Mask 0x%x\n", Mask
);
90 if (pAccel
->fVirt
& FVIRTKEY
)
92 /* This is a virtual key. Process WM_(SYS)KEYDOWN messages. */
93 if (pMsg
->message
== WM_KEYDOWN
|| pMsg
->message
== WM_SYSKEYDOWN
)
95 /* Check virtual key and SHIFT, CTRL, LALT state */
96 if (pMsg
->wParam
== pAccel
->key
&& Mask
== (pAccel
->fVirt
& (FSHIFT
| FCONTROL
| FALT
)))
104 /* This is a char code. Process WM_(SYS)CHAR messages. */
105 if (pMsg
->message
== WM_CHAR
|| pMsg
->message
== WM_SYSCHAR
)
107 /* Check char code and LALT state only */
108 if (pMsg
->wParam
== pAccel
->key
&& (Mask
& FALT
) == (pAccel
->fVirt
& FALT
))
117 /* Don't translate this msg */
118 TRACE("IntTranslateAccelerator returns FALSE\n");
122 /* Check if accelerator is associated with menu command */
123 hMenu
= (Window
->style
& WS_CHILD
) ? 0 : (HMENU
)Window
->IDMenu
;
125 MenuObject
= IntGetMenuObject(hMenu
);
128 nPos
= IntGetMenuItemByFlag(MenuObject
,
134 if (nPos
!= (UINT
)-1)
135 hSubMenu
= MenuItem
->hSubMenu
;
141 /* Check system menu now */
142 hMenu
= Window
->SystemMenu
;
143 hSubMenu
= hMenu
; /* system menu is a popup menu */
144 MenuObject
= IntGetMenuObject(hMenu
);
147 nPos
= IntGetMenuItemByFlag(MenuObject
,
153 if (nPos
!= (UINT
)-1)
154 hSubMenu
= MenuItem
->hSubMenu
;
160 /* If this is a menu item, there is no capturing enabled and
161 window is not disabled, send WM_INITMENU */
162 if (hMenu
&& !IntGetCaptureWindow())
164 co_IntSendMessage(hWnd
, WM_INITMENU
, (WPARAM
)hMenu
, 0L);
167 nPos
= IntFindSubMenu(&hMenu
, hSubMenu
);
168 TRACE("hSysMenu = %p, hSubMenu = %p, nPos = %d\n", hMenu
, hSubMenu
, nPos
);
169 co_IntSendMessage(hWnd
, WM_INITMENUPOPUP
, (WPARAM
)hSubMenu
, MAKELPARAM(nPos
, TRUE
));
173 /* Don't send any message if:
175 - menu item is disabled
176 - this is window menu and window is minimized */
177 if (!(Window
->style
& WS_DISABLED
) &&
178 !(hMenu
&& IntGetMenuState(hMenu
, pAccel
->cmd
, MF_BYCOMMAND
) & (MF_DISABLED
|MF_GRAYED
)) &&
179 !(hMenu
&& hMenu
== (HMENU
)Window
->IDMenu
&& !(Window
->style
& WS_MINIMIZED
)))
181 /* If this is system menu item, send WM_SYSCOMMAND, otherwise send WM_COMMAND */
182 if (hMenu
&& hMenu
== Window
->SystemMenu
)
184 TRACE("Sending WM_SYSCOMMAND, wParam=%0x\n", pAccel
->cmd
);
185 co_IntSendMessage(hWnd
, WM_SYSCOMMAND
, pAccel
->cmd
, 0x00010000L
);
189 TRACE("Sending WM_COMMAND, wParam=%0x\n", 0x10000 | pAccel
->cmd
);
190 co_IntSendMessage(hWnd
, WM_COMMAND
, 0x10000 | pAccel
->cmd
, 0L);
194 TRACE("IntTranslateAccelerator returns TRUE\n");
199 /* SYSCALLS *****************************************************************/
204 NtUserCopyAcceleratorTable(
209 PACCELERATOR_TABLE Accel
;
213 TRACE("Enter NtUserCopyAcceleratorTable\n");
216 Accel
= UserGetAccelObject(hAccel
);
222 /* If Entries is NULL return table size */
225 RETURN(Accel
->Count
);
229 if (Accel
->Count
< EntriesCount
)
230 EntriesCount
= Accel
->Count
;
236 ProbeForWrite(Entries
, EntriesCount
*sizeof(Entries
[0]), 4);
238 for (Ret
= 0; Ret
< EntriesCount
; Ret
++)
240 Entries
[Ret
].fVirt
= Accel
->Table
[Ret
].fVirt
;
241 Entries
[Ret
].key
= Accel
->Table
[Ret
].key
;
242 Entries
[Ret
].cmd
= Accel
->Table
[Ret
].cmd
;
245 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
247 SetLastNtError(_SEH2_GetExceptionCode());
255 TRACE("Leave NtUserCopyAcceleratorTable, ret=%i\n", _ret_
);
262 NtUserCreateAcceleratorTable(
266 PACCELERATOR_TABLE Accel
;
269 NTSTATUS Status
= STATUS_SUCCESS
;
270 DECLARE_RETURN(HACCEL
);
272 TRACE("Enter NtUserCreateAcceleratorTable(Entries %p, EntriesCount %d)\n",
273 Entries
, EntriesCount
);
274 UserEnterExclusive();
276 if (!Entries
|| EntriesCount
<= 0)
278 SetLastNtError(STATUS_INVALID_PARAMETER
);
279 RETURN( (HACCEL
) NULL
);
282 Accel
= UserCreateObject(gHandleTable
, NULL
, (PHANDLE
)&hAccel
, otAccel
, sizeof(ACCELERATOR_TABLE
));
286 SetLastNtError(STATUS_NO_MEMORY
);
287 RETURN( (HACCEL
) NULL
);
290 Accel
->Count
= EntriesCount
;
291 Accel
->Table
= ExAllocatePoolWithTag(PagedPool
, EntriesCount
* sizeof(ACCEL
), USERTAG_ACCEL
);
292 if (Accel
->Table
== NULL
)
294 UserDereferenceObject(Accel
);
295 UserDeleteObject(hAccel
, otAccel
);
296 SetLastNtError(STATUS_NO_MEMORY
);
297 RETURN( (HACCEL
) NULL
);
302 ProbeForRead(Entries
, EntriesCount
* sizeof(ACCEL
), 4);
304 for (Index
= 0; Index
< EntriesCount
; Index
++)
306 Accel
->Table
[Index
].fVirt
= Entries
[Index
].fVirt
& FVIRT_MASK
;
307 if(Accel
->Table
[Index
].fVirt
& FVIRTKEY
)
309 Accel
->Table
[Index
].key
= Entries
[Index
].key
;
313 RtlMultiByteToUnicodeN(&Accel
->Table
[Index
].key
,
316 (PCSTR
)&Entries
[Index
].key
,
320 Accel
->Table
[Index
].cmd
= Entries
[Index
].cmd
;
323 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
325 Status
= _SEH2_GetExceptionCode();
329 if (!NT_SUCCESS(Status
))
331 ExFreePoolWithTag(Accel
->Table
, USERTAG_ACCEL
);
332 UserDereferenceObject(Accel
);
333 UserDeleteObject(hAccel
, otAccel
);
334 SetLastNtError(Status
);
335 RETURN( (HACCEL
) NULL
);
338 /* FIXME: Save HandleTable in a list somewhere so we can clean it up again */
343 TRACE("Leave NtUserCreateAcceleratorTable(Entries %p, EntriesCount %d) = %x\n",
344 Entries
, EntriesCount
, _ret_
);
351 NtUserDestroyAcceleratorTable(
354 PACCELERATOR_TABLE Accel
;
355 DECLARE_RETURN(BOOLEAN
);
357 /* FIXME: If the handle table is from a call to LoadAcceleratorTable, decrement it's
358 usage count (and return TRUE).
359 FIXME: Destroy only tables created using CreateAcceleratorTable.
362 TRACE("NtUserDestroyAcceleratorTable(Table %x)\n", hAccel
);
363 UserEnterExclusive();
365 if (!(Accel
= UserGetAccelObject(hAccel
)))
370 if (Accel
->Table
!= NULL
)
372 ExFreePoolWithTag(Accel
->Table
, USERTAG_ACCEL
);
376 UserDeleteObject(hAccel
, otAccel
);
381 TRACE("Leave NtUserDestroyAcceleratorTable(Table %x) = %i\n", hAccel
,_ret_
);
388 NtUserTranslateAccelerator(
391 LPMSG pUnsafeMessage
)
394 PACCELERATOR_TABLE Accel
= NULL
;
397 USER_REFERENCE_ENTRY AccelRef
, WindowRef
;
400 TRACE("NtUserTranslateAccelerator(hWnd %x, Table %x, Message %p)\n",
401 hWnd
, hAccel
, pUnsafeMessage
);
411 ProbeForRead(pUnsafeMessage
, sizeof(MSG
), 4);
412 RtlCopyMemory(&Message
, pUnsafeMessage
, sizeof(MSG
));
414 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
416 SetLastNtError(_SEH2_GetExceptionCode());
417 _SEH2_YIELD(RETURN( 0));
421 if ((Message
.message
!= WM_KEYDOWN
) &&
422 (Message
.message
!= WM_SYSKEYDOWN
) &&
423 (Message
.message
!= WM_SYSCHAR
) &&
424 (Message
.message
!= WM_CHAR
))
429 Accel
= UserGetAccelObject(hAccel
);
435 UserRefObjectCo(Accel
, &AccelRef
);
437 Window
= UserGetWindowObject(hWnd
);
443 UserRefObjectCo(Window
, &WindowRef
);
445 /* FIXME: Associate AcceleratorTable with the current thread */
447 for (i
= 0; i
< Accel
->Count
; i
++)
449 if (co_IntTranslateAccelerator(Window
, &Message
, &Accel
->Table
[i
]))
451 TRACE("NtUserTranslateAccelerator returns 1\n");
455 /* Undocumented feature... */
456 if (Accel
->Table
[i
].fVirt
& FVIRT_TBL_END
)
463 if (Window
) UserDerefObjectCo(Window
);
464 if (Accel
) UserDerefObjectCo(Accel
);
466 TRACE("NtUserTranslateAccelerator returns 0\n");