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.
19 /* $Id: accel.c,v 1.8 2003/07/10 21:04:31 chorns Exp $
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 ******************************************************************/
36 /* FUNCTIONS *****************************************************************/
38 /* RT_ACCELERATOR resources are arrays of RES_ACCEL structures */
39 typedef struct _RES_ACCEL
47 /* ACCELERATOR TABLES CACHE */
49 typedef struct _USER_ACCEL_CACHE_ENTRY
51 struct _USER_ACCEL_CACHE_ENTRY
* Next
;
52 ULONG_PTR Usage
; /* how many times the table has been loaded */
53 HACCEL Object
; /* handle to the NtUser accelerator table object */
54 HGLOBAL Data
; /* base address of the resource data */
56 U32_ACCEL_CACHE_ENTRY
;
58 /* Lock guarding the cache */
59 CRITICAL_SECTION U32AccelCacheLock
;
62 U32_ACCEL_CACHE_ENTRY
* U32AccelCache
= NULL
;
64 U32_ACCEL_CACHE_ENTRY
** WINAPI
U32AccelCacheFind(HANDLE
, HGLOBAL
);
65 void WINAPI
U32AccelCacheAdd(HACCEL
, HGLOBAL
);
67 /* Look up a handle or resource address in the cache */
68 U32_ACCEL_CACHE_ENTRY
** WINAPI
U32AccelCacheFind(HANDLE Object
, HGLOBAL Data
)
71 to avoid using a double-link list and still allow elements to be removed,
72 return a pointer to the list link that points to the desired entry
74 U32_ACCEL_CACHE_ENTRY
** ppEntry
= &U32AccelCache
;
76 for(; *ppEntry
; ppEntry
= &((*ppEntry
)->Next
))
77 if((*ppEntry
)->Object
== Object
|| (*ppEntry
)->Data
== Data
) break;
82 /* Allocate an entry and insert it into the cache */
83 void WINAPI
U32AccelCacheAdd(HACCEL Object
, HGLOBAL Data
)
85 U32_ACCEL_CACHE_ENTRY
* pEntry
=
86 LocalAlloc(LMEM_FIXED
, sizeof(U32_ACCEL_CACHE_ENTRY
));
88 /* failed to allocate an entry - not critical */
89 if(pEntry
== NULL
) return;
91 /* initialize the entry */
93 pEntry
->Object
= Object
;
96 /* insert the entry into the cache */
97 pEntry
->Next
= U32AccelCache
;
98 U32AccelCache
= pEntry
;
101 /* Create an accelerator table from a loaded resource */
102 HACCEL WINAPI
U32LoadAccelerators(HINSTANCE hInstance
, HRSRC hTableRes
)
104 HGLOBAL hAccTableData
;
105 HACCEL hAccTable
= NULL
;
106 U32_ACCEL_CACHE_ENTRY
* pEntry
;
107 RES_ACCEL
* pAccTableResData
;
111 ACCEL
* pAccTableData
;
113 /* load the accelerator table */
114 hAccTableData
= LoadResource(hInstance
, hTableRes
);
117 if(hAccTableData
== NULL
) return NULL
;
119 RtlEnterCriticalSection(&U32AccelCacheLock
);
121 /* see if this accelerator table has already been loaded */
122 pEntry
= *U32AccelCacheFind(NULL
, hAccTableData
);
124 /* accelerator table already loaded */
127 /* increment the reference count */
130 /* return the existing object */
131 hAccTable
= pEntry
->Object
;
137 /* count the number of entries in the table */
138 p
= pAccTableResData
= (RES_ACCEL
*)hAccTableData
;
142 /* FIXME??? unknown flag 0x60 stops the scan */
143 if(p
->fVirt
& 0x60) break;
148 /* flag 0x80 marks the last entry of the table */
149 if(p
->fVirt
& 0x80) break;
152 /* allocate the buffer for the table to be passed to Win32K */
153 pAccTableData
= LocalAlloc(LMEM_FIXED
, i
* sizeof(ACCEL
));
156 if(pAccTableData
== NULL
) goto l_Leave
;
159 for(j
= 0; j
< i
; ++ j
)
161 pAccTableData
[j
].fVirt
= pAccTableResData
[j
].fVirt
;
162 pAccTableData
[j
].key
= pAccTableResData
[j
].key
;
163 pAccTableData
[j
].cmd
= pAccTableResData
[j
].cmd
;
166 /* create a new accelerator table object */
167 hAccTable
= NtUserCreateAcceleratorTable(pAccTableData
, i
);
169 /* free the buffer */
170 LocalFree(pAccTableData
);
173 if(hAccTable
== NULL
) goto l_Leave
;
175 /* success - cache the object */
176 U32AccelCacheAdd(hAccTable
, pAccTableResData
);
179 RtlLeaveCriticalSection(&U32AccelCacheLock
);
183 /* Checks if a message can be translated through an accelerator table */
184 BOOL WINAPI
U32IsValidAccelMessage(UINT uMsg
)
199 /* WIN32 FUNCTIONS ***********************************************************/
202 * Dereference the specified accelerator table, removing it from the cache and
203 * deleting the associated NtUser object as appropriate
207 BOOL WINAPI
DestroyAcceleratorTable(HACCEL hAccel
)
209 U32_ACCEL_CACHE_ENTRY
** ppEntry
;
210 ULONG_PTR nUsage
= 0;
212 RtlEnterCriticalSection(&U32AccelCacheLock
);
214 /* see if this accelerator table has been cached */
215 ppEntry
= U32AccelCacheFind(hAccel
, NULL
);
217 /* accelerator table cached */
220 U32_ACCEL_CACHE_ENTRY
* pEntry
= *ppEntry
;
222 /* decrement the reference count */
223 nUsage
= pEntry
->Usage
= pEntry
->Usage
- 1;
225 /* reference count now zero: destroy the cache entry */
228 /* unlink the cache entry */
229 *ppEntry
= pEntry
->Next
;
231 /* free the cache entry */
236 RtlLeaveCriticalSection(&U32AccelCacheLock
);
238 if(nUsage
> 0) return FALSE
;
240 /* destroy the object */
241 return NtUserDestroyAcceleratorTable(hAccel
);
246 * Create an accelerator table from a named resource
250 HACCEL WINAPI
LoadAcceleratorsW(HINSTANCE hInstance
, LPCWSTR lpTableName
)
252 return U32LoadAccelerators
255 FindResourceExW(hInstance
, MAKEINTRESOURCEW(RT_ACCELERATOR
), lpTableName
, 0)
263 HACCEL WINAPI
LoadAcceleratorsA(HINSTANCE hInstance
, LPCSTR lpTableName
)
265 return U32LoadAccelerators
268 FindResourceExA(hInstance
, MAKEINTRESOURCEA(RT_ACCELERATOR
), lpTableName
, 0)
273 * Translate a key press into a WM_COMMAND message
277 int WINAPI
TranslateAcceleratorW(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
279 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
281 return NtUserTranslateAccelerator(hWnd
, hAccTable
, lpMsg
);
287 int WINAPI CopyAcceleratorTableW
294 return NtUserCopyAcceleratorTable(hAccelSrc
, lpAccelDst
, cAccelEntries
);
300 HACCEL WINAPI
CreateAcceleratorTableW(LPACCEL lpaccl
, int cEntries
)
302 return NtUserCreateAcceleratorTable(lpaccl
, cEntries
);
309 int WINAPI CopyAcceleratorTableA
318 cAccelEntries
= CopyAcceleratorTableW(hAccelSrc
, lpAccelDst
, cAccelEntries
);
320 if(cAccelEntries
== 0) return 0;
322 for(i
= 0; i
< cAccelEntries
; ++ i
)
323 if(!(lpAccelDst
[i
].fVirt
& FVIRTKEY
))
325 NTSTATUS nErrCode
= RtlUnicodeToMultiByteN
327 (PCHAR
)&lpAccelDst
[i
].key
,
328 sizeof(lpAccelDst
[i
].key
),
330 (PWCHAR
)&lpAccelDst
[i
].key
,
331 sizeof(lpAccelDst
[i
].key
)
334 if(!NT_SUCCESS(nErrCode
)) lpAccelDst
[i
].key
= 0;
337 return cAccelEntries
;
344 HACCEL WINAPI
CreateAcceleratorTableA(LPACCEL lpaccl
, int cEntries
)
348 for(i
= 0; i
< cEntries
; ++ i
)
351 NTSTATUS nErrCode
= RtlMultiByteToUnicodeN
353 (PWCHAR
)&lpaccl
[i
].key
,
354 sizeof(lpaccl
[i
].key
),
356 (PCHAR
)&lpaccl
[i
].key
,
357 sizeof(lpaccl
[i
].key
)
360 if(!NT_SUCCESS(nErrCode
)) lpaccl
[i
].key
= -1;
363 return CreateAcceleratorTableW(lpaccl
, cEntries
);
370 int WINAPI
TranslateAcceleratorA(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
376 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
379 RtlMultiByteToUnicodeN(&wChar
, sizeof(wChar
), NULL
, &cChar
, sizeof(cChar
));
383 SetLastError(RtlNtStatusToDosError(nErrCode
));
387 return TranslateAcceleratorW(hWnd
, hAccTable
, &mCopy
);