3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Accelerator tables
24 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
26 * 09/05/2001 CSH Created
27 * 08/07/2003 KJK Fully implemented
30 /* INCLUDES ******************************************************************/
32 #include <user32/accel.h>
33 #include <win32k/ntuser.h>
35 /* FUNCTIONS *****************************************************************/
37 /* Lock guarding the cache */
38 CRITICAL_SECTION U32AccelCacheLock;
41 U32_ACCEL_CACHE_ENTRY * U32AccelCache = NULL;
43 /* Look up a handle or resource address in the cache */
44 U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE Object, HGLOBAL Data)
47 to avoid using a double-link list and still allow elements to be removed,
48 return a pointer to the list link that points to the desired entry
50 U32_ACCEL_CACHE_ENTRY ** ppEntry = &U32AccelCache;
52 for(; *ppEntry; ppEntry = &((*ppEntry)->Next))
53 if((*ppEntry)->Object == Object || (*ppEntry)->Data == Data) break;
58 /* Allocate an entry and insert it into the cache */
59 void WINAPI U32AccelCacheAdd(HACCEL Object, HGLOBAL Data)
61 U32_ACCEL_CACHE_ENTRY * pEntry =
62 LocalAlloc(LMEM_FIXED, sizeof(U32_ACCEL_CACHE_ENTRY));
64 /* failed to allocate an entry - not critical */
65 if(pEntry == NULL) return;
67 /* initialize the entry */
69 pEntry->Object = Object;
72 /* insert the entry into the cache */
73 pEntry->Next = U32AccelCache;
74 U32AccelCache = pEntry;
77 /* Create an accelerator table from a loaded resource */
78 HACCEL WINAPI U32LoadAccelerators(HINSTANCE hInstance, HRSRC hTableRes)
80 HGLOBAL hAccTableData;
81 HACCEL hAccTable = NULL;
82 U32_ACCEL_CACHE_ENTRY * pEntry;
83 RES_ACCEL * pAccTableResData;
87 ACCEL * pAccTableData;
89 /* load the accelerator table */
90 hAccTableData = LoadResource(hInstance, hTableRes);
93 if(hAccTableData == NULL) return NULL;
95 RtlEnterCriticalSection(&U32AccelCacheLock);
97 /* see if this accelerator table has already been loaded */
98 pEntry = *U32AccelCacheFind(NULL, hAccTableData);
100 /* accelerator table already loaded */
103 /* increment the reference count */
106 /* return the existing object */
107 hAccTable = pEntry->Object;
113 /* count the number of entries in the table */
114 p = pAccTableResData = (RES_ACCEL *)hAccTableData;
118 /* FIXME??? unknown flag 0x60 stops the scan */
119 if(p->fVirt & 0x60) break;
124 /* flag 0x80 marks the last entry of the table */
125 if(p->fVirt & 0x80) break;
128 /* allocate the buffer for the table to be passed to Win32K */
129 pAccTableData = LocalAlloc(LMEM_FIXED, i * sizeof(ACCEL));
132 if(pAccTableData == NULL) goto l_Leave;
135 for(j = 0; j < i; ++ j)
137 pAccTableData[j].fVirt = pAccTableResData[j].fVirt;
138 pAccTableData[j].key = pAccTableResData[j].key;
139 pAccTableData[j].cmd = pAccTableResData[j].cmd;
142 /* create a new accelerator table object */
143 hAccTable = NtUserCreateAcceleratorTable(pAccTableData, i);
145 /* free the buffer */
146 LocalFree(pAccTableData);
149 if(hAccTable == NULL) goto l_Leave;
151 /* success - cache the object */
152 U32AccelCacheAdd(hAccTable, pAccTableResData);
155 RtlLeaveCriticalSection(&U32AccelCacheLock);
159 /* Checks if a message can be translated through an accelerator table */
160 BOOL WINAPI U32IsValidAccelMessage(UINT uMsg)
175 /* WIN32 FUNCTIONS ***********************************************************/
178 * Dereference the specified accelerator table, removing it from the cache and
179 * deleting the associated NtUser object as appropriate
183 BOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel)
185 U32_ACCEL_CACHE_ENTRY ** ppEntry;
186 ULONG_PTR nUsage = 0;
188 RtlEnterCriticalSection(&U32AccelCacheLock);
190 /* see if this accelerator table has been cached */
191 ppEntry = U32AccelCacheFind(hAccel, NULL);
193 /* accelerator table cached */
196 U32_ACCEL_CACHE_ENTRY * pEntry = *ppEntry;
198 /* decrement the reference count */
199 nUsage = pEntry->Usage = pEntry->Usage - 1;
201 /* reference count now zero: destroy the cache entry */
204 /* unlink the cache entry */
205 *ppEntry = pEntry->Next;
207 /* free the cache entry */
212 RtlLeaveCriticalSection(&U32AccelCacheLock);
214 if(nUsage > 0) return FALSE;
216 /* destroy the object */
217 return NtUserDestroyAcceleratorTable(hAccel);
222 * Create an accelerator table from a named resource
226 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance, LPCWSTR lpTableName)
228 return U32LoadAccelerators
231 FindResourceExW(hInstance, MAKEINTRESOURCEW(RT_ACCELERATOR), lpTableName, 0)
239 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance, LPCSTR lpTableName)
243 Accel = FindResourceExA(hInstance, MAKEINTRESOURCEA(RT_ACCELERATOR), lpTableName, 0);
249 return U32LoadAccelerators(hInstance, Accel);
253 * Translate a key press into a WM_COMMAND message
257 int WINAPI TranslateAcceleratorW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
259 if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
261 return NtUserTranslateAccelerator(hWnd, hAccTable, lpMsg);
267 int WINAPI CopyAcceleratorTableW
274 return NtUserCopyAcceleratorTable(hAccelSrc, lpAccelDst, cAccelEntries);
280 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccl, int cEntries)
282 return NtUserCreateAcceleratorTable(lpaccl, cEntries);
289 int WINAPI CopyAcceleratorTableA
298 cAccelEntries = CopyAcceleratorTableW(hAccelSrc, lpAccelDst, cAccelEntries);
300 if(cAccelEntries == 0) return 0;
302 for(i = 0; i < cAccelEntries; ++ i)
303 if(!(lpAccelDst[i].fVirt & FVIRTKEY))
305 NTSTATUS nErrCode = RtlUnicodeToMultiByteN
307 (PCHAR)&lpAccelDst[i].key,
308 sizeof(lpAccelDst[i].key),
310 (PWCHAR)&lpAccelDst[i].key,
311 sizeof(lpAccelDst[i].key)
314 if(!NT_SUCCESS(nErrCode)) lpAccelDst[i].key = 0;
317 return cAccelEntries;
324 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccl, int cEntries)
328 for(i = 0; i < cEntries; ++ i)
331 NTSTATUS nErrCode = RtlMultiByteToUnicodeN
333 (PWCHAR)&lpaccl[i].key,
334 sizeof(lpaccl[i].key),
336 (PCHAR)&lpaccl[i].key,
337 sizeof(lpaccl[i].key)
340 if(!NT_SUCCESS(nErrCode)) lpaccl[i].key = -1;
343 return CreateAcceleratorTableW(lpaccl, cEntries);
350 int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
357 if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
360 RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar));
364 SetLastError(RtlNtStatusToDosError(nErrCode));
368 return TranslateAcceleratorW(hWnd, hAccTable, &mCopy);