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.
20 * PROJECT: ReactOS user32.dll
21 * FILE: lib/user32/windows/input.c
22 * PURPOSE: Accelerator tables
23 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
25 * 09/05/2001 CSH Created
26 * 08/07/2003 KJK Fully implemented
29 /* INCLUDES ******************************************************************/
33 #include <wine/debug.h>
35 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
43 } PE_ACCEL
, *LPPE_ACCEL
;
46 typedef struct _USER_ACCEL_CACHE_ENTRY
48 struct _USER_ACCEL_CACHE_ENTRY
* Next
;
49 ULONG_PTR Usage
; /* how many times the table has been loaded */
50 HACCEL Object
; /* handle to the NtUser accelerator table object */
51 HGLOBAL Data
; /* base address of the resource data */
53 U32_ACCEL_CACHE_ENTRY
;
55 /* FUNCTIONS *****************************************************************/
57 /* Lock guarding the cache */
58 CRITICAL_SECTION U32AccelCacheLock
;
61 U32_ACCEL_CACHE_ENTRY
* U32AccelCache
= NULL
;
63 /* Look up a handle or resource address in the cache */
64 U32_ACCEL_CACHE_ENTRY
** WINAPI
U32AccelCacheFind(HANDLE Object
, HGLOBAL Data
)
67 to avoid using a double-link list and still allow elements to be removed,
68 return a pointer to the list link that points to the desired entry
70 U32_ACCEL_CACHE_ENTRY
** ppEntry
= &U32AccelCache
;
72 for(; *ppEntry
; ppEntry
= &((*ppEntry
)->Next
))
73 if((*ppEntry
)->Object
== Object
|| (*ppEntry
)->Data
== Data
) break;
78 /* Allocate an entry and insert it into the cache */
79 void WINAPI
U32AccelCacheAdd(HACCEL Object
, HGLOBAL Data
)
81 U32_ACCEL_CACHE_ENTRY
* pEntry
=
82 LocalAlloc(LMEM_FIXED
, sizeof(U32_ACCEL_CACHE_ENTRY
));
84 /* failed to allocate an entry - not critical */
85 if(pEntry
== NULL
) return;
87 /* initialize the entry */
89 pEntry
->Object
= Object
;
92 /* insert the entry into the cache */
93 pEntry
->Next
= U32AccelCache
;
94 U32AccelCache
= pEntry
;
97 /* Create an accelerator table from a loaded resource */
98 HACCEL WINAPI
U32LoadAccelerators(HINSTANCE hInstance
, HRSRC hTableRes
)
100 HGLOBAL hAccTableData
;
101 HACCEL hAccTable
= NULL
;
102 U32_ACCEL_CACHE_ENTRY
* pEntry
;
103 PE_ACCEL
* pAccTableResData
;
106 ACCEL
* pAccTableData
;
108 /* load the accelerator table */
109 hAccTableData
= LoadResource(hInstance
, hTableRes
);
112 if(hAccTableData
== NULL
) return NULL
;
114 EnterCriticalSection(&U32AccelCacheLock
);
116 /* see if this accelerator table has already been loaded */
117 pEntry
= *U32AccelCacheFind(NULL
, hAccTableData
);
119 /* accelerator table already loaded */
122 /* increment the reference count */
125 /* return the existing object */
126 hAccTable
= pEntry
->Object
;
132 /* determine the number of entries in the table */
133 i
= SizeofResource(hInstance
, hTableRes
) / sizeof(PE_ACCEL
);
135 /* allocate the buffer for the table to be passed to Win32K */
136 pAccTableData
= LocalAlloc(LMEM_FIXED
, i
* sizeof(ACCEL
));
139 if(pAccTableData
== NULL
) goto l_Leave
;
141 pAccTableResData
= (PE_ACCEL
*)hAccTableData
;
144 for(j
= 0; j
< i
; ++ j
)
146 pAccTableData
[j
].fVirt
= pAccTableResData
[j
].fVirt
;
147 pAccTableData
[j
].key
= pAccTableResData
[j
].key
;
148 pAccTableData
[j
].cmd
= pAccTableResData
[j
].cmd
;
150 pAccTableData
[i
- 1].fVirt
|= 0x80;
152 /* create a new accelerator table object */
153 hAccTable
= NtUserCreateAcceleratorTable(pAccTableData
, i
);
155 /* free the buffer */
156 LocalFree(pAccTableData
);
159 if(hAccTable
== NULL
) goto l_Leave
;
161 /* success - cache the object */
162 U32AccelCacheAdd(hAccTable
, pAccTableResData
);
165 LeaveCriticalSection(&U32AccelCacheLock
);
169 /* Checks if a message can be translated through an accelerator table */
170 BOOL WINAPI
U32IsValidAccelMessage(UINT uMsg
)
187 /* WIN32 FUNCTIONS ***********************************************************/
190 * Dereference the specified accelerator table, removing it from the cache and
191 * deleting the associated NtUser object as appropriate
195 BOOL WINAPI
DestroyAcceleratorTable(HACCEL hAccel
)
197 U32_ACCEL_CACHE_ENTRY
** ppEntry
;
198 ULONG_PTR nUsage
= 0;
203 EnterCriticalSection(&U32AccelCacheLock
);
205 /* see if this accelerator table has been cached */
206 ppEntry
= U32AccelCacheFind(hAccel
, NULL
);
208 /* accelerator table cached */
211 U32_ACCEL_CACHE_ENTRY
* pEntry
= *ppEntry
;
213 /* decrement the reference count */
214 nUsage
= pEntry
->Usage
= pEntry
->Usage
- 1;
216 /* reference count now zero: destroy the cache entry */
219 /* unlink the cache entry */
220 *ppEntry
= pEntry
->Next
;
222 /* free the cache entry */
227 LeaveCriticalSection(&U32AccelCacheLock
);
229 if(nUsage
> 0) return FALSE
;
231 /* destroy the object */
232 return NtUserDestroyAcceleratorTable(hAccel
);
237 * Create an accelerator table from a named resource
241 HACCEL WINAPI
LoadAcceleratorsW(HINSTANCE hInstance
, LPCWSTR lpTableName
)
243 return U32LoadAccelerators
246 FindResourceExW(hInstance
, (LPCWSTR
) RT_ACCELERATOR
, lpTableName
, 0)
254 HACCEL WINAPI
LoadAcceleratorsA(HINSTANCE hInstance
, LPCSTR lpTableName
)
258 Accel
= FindResourceExA(hInstance
, (LPCSTR
) RT_ACCELERATOR
, lpTableName
, 0);
264 return U32LoadAccelerators(hInstance
, Accel
);
268 * Translate a key press into a WM_COMMAND message
272 int WINAPI
TranslateAcceleratorW(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
274 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
276 return NtUserTranslateAccelerator(hWnd
, hAccTable
, lpMsg
);
283 int WINAPI CopyAcceleratorTableA
286 LPACCEL lpAccelDst
, /* can be NULL */
292 cAccelEntries
= CopyAcceleratorTableW(hAccelSrc
, lpAccelDst
, cAccelEntries
);
294 if (lpAccelDst
== NULL
) return cAccelEntries
;
296 for(i
= 0; i
< cAccelEntries
; ++ i
)
297 if(!(lpAccelDst
[i
].fVirt
& FVIRTKEY
))
299 NTSTATUS nErrCode
= RtlUnicodeToMultiByteN(
300 (PCHAR
)&lpAccelDst
[i
].key
,
301 sizeof(lpAccelDst
[i
].key
),
303 (PWCHAR
)&lpAccelDst
[i
].key
,
304 sizeof(lpAccelDst
[i
].key
)
307 if(!NT_SUCCESS(nErrCode
)) lpAccelDst
[i
].key
= 0;
310 return cAccelEntries
;
317 HACCEL WINAPI
CreateAcceleratorTableA(LPACCEL lpaccl
, int cEntries
)
321 if (!cEntries
|| !lpaccl
) return (HACCEL
)0;
323 for(i
= 0; i
< cEntries
; ++ i
)
326 NTSTATUS nErrCode
= RtlMultiByteToUnicodeN
328 (PWCHAR
)&lpaccl
[i
].key
,
329 sizeof(lpaccl
[i
].key
),
331 (PCHAR
)&lpaccl
[i
].key
,
332 sizeof(lpaccl
[i
].key
)
335 if(!NT_SUCCESS(nErrCode
)) lpaccl
[i
].key
= -1;
338 return CreateAcceleratorTableW(lpaccl
, cEntries
);
345 int WINAPI
TranslateAcceleratorA(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
352 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
354 Status
= RtlMultiByteToUnicodeN(&wChar
, sizeof(wChar
), NULL
, &cChar
, sizeof(cChar
));
355 if(!NT_SUCCESS(Status
))
357 SetLastError(RtlNtStatusToDosError(Status
));
361 return TranslateAcceleratorW(hWnd
, hAccTable
, &mCopy
);