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 ******************************************************************/
34 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
42 } PE_ACCEL
, *LPPE_ACCEL
;
44 /* FUNCTIONS *****************************************************************/
46 /* Lock guarding the cache */
47 CRITICAL_SECTION U32AccelCacheLock
;
50 U32_ACCEL_CACHE_ENTRY
* U32AccelCache
= NULL
;
52 /* Look up a handle or resource address in the cache */
53 U32_ACCEL_CACHE_ENTRY
** WINAPI
U32AccelCacheFind(HANDLE Object
, HGLOBAL Data
)
56 to avoid using a double-link list and still allow elements to be removed,
57 return a pointer to the list link that points to the desired entry
59 U32_ACCEL_CACHE_ENTRY
** ppEntry
= &U32AccelCache
;
61 for(; *ppEntry
; ppEntry
= &((*ppEntry
)->Next
))
62 if((*ppEntry
)->Object
== Object
|| (*ppEntry
)->Data
== Data
) break;
67 /* Allocate an entry and insert it into the cache */
68 void WINAPI
U32AccelCacheAdd(HACCEL Object
, HGLOBAL Data
)
70 U32_ACCEL_CACHE_ENTRY
* pEntry
=
71 LocalAlloc(LMEM_FIXED
, sizeof(U32_ACCEL_CACHE_ENTRY
));
73 /* failed to allocate an entry - not critical */
74 if(pEntry
== NULL
) return;
76 /* initialize the entry */
78 pEntry
->Object
= Object
;
81 /* insert the entry into the cache */
82 pEntry
->Next
= U32AccelCache
;
83 U32AccelCache
= pEntry
;
86 /* Create an accelerator table from a loaded resource */
87 HACCEL WINAPI
U32LoadAccelerators(HINSTANCE hInstance
, HRSRC hTableRes
)
89 HGLOBAL hAccTableData
;
90 HACCEL hAccTable
= NULL
;
91 U32_ACCEL_CACHE_ENTRY
* pEntry
;
92 PE_ACCEL
* pAccTableResData
;
95 ACCEL
* pAccTableData
;
97 /* load the accelerator table */
98 hAccTableData
= LoadResource(hInstance
, hTableRes
);
101 if(hAccTableData
== NULL
) return NULL
;
103 EnterCriticalSection(&U32AccelCacheLock
);
105 /* see if this accelerator table has already been loaded */
106 pEntry
= *U32AccelCacheFind(NULL
, hAccTableData
);
108 /* accelerator table already loaded */
111 /* increment the reference count */
114 /* return the existing object */
115 hAccTable
= pEntry
->Object
;
121 /* determine the number of entries in the table */
122 i
= SizeofResource(hInstance
, hTableRes
) / sizeof(PE_ACCEL
);
124 /* allocate the buffer for the table to be passed to Win32K */
125 pAccTableData
= LocalAlloc(LMEM_FIXED
, i
* sizeof(ACCEL
));
128 if(pAccTableData
== NULL
) goto l_Leave
;
130 pAccTableResData
= (PE_ACCEL
*)hAccTableData
;
133 for(j
= 0; j
< i
; ++ j
)
135 pAccTableData
[j
].fVirt
= pAccTableResData
[j
].fVirt
;
136 pAccTableData
[j
].key
= pAccTableResData
[j
].key
;
137 pAccTableData
[j
].cmd
= pAccTableResData
[j
].cmd
;
139 pAccTableData
[i
- 1].fVirt
|= 0x80;
141 /* create a new accelerator table object */
142 hAccTable
= NtUserCreateAcceleratorTable(pAccTableData
, i
);
144 /* free the buffer */
145 LocalFree(pAccTableData
);
148 if(hAccTable
== NULL
) goto l_Leave
;
150 /* success - cache the object */
151 U32AccelCacheAdd(hAccTable
, pAccTableResData
);
154 LeaveCriticalSection(&U32AccelCacheLock
);
158 /* Checks if a message can be translated through an accelerator table */
159 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 EnterCriticalSection(&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 LeaveCriticalSection(&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
292 LPACCEL lpAccelDst
, /* can be NULL */
298 cAccelEntries
= CopyAcceleratorTableW(hAccelSrc
, lpAccelDst
, cAccelEntries
);
300 if (lpAccelDst
== NULL
) return cAccelEntries
;
302 for(i
= 0; i
< cAccelEntries
; ++ i
)
303 if(!(lpAccelDst
[i
].fVirt
& FVIRTKEY
))
305 NTSTATUS nErrCode
= RtlUnicodeToMultiByteN(
306 (PCHAR
)&lpAccelDst
[i
].key
,
307 sizeof(lpAccelDst
[i
].key
),
309 (PWCHAR
)&lpAccelDst
[i
].key
,
310 sizeof(lpAccelDst
[i
].key
)
313 if(!NT_SUCCESS(nErrCode
)) lpAccelDst
[i
].key
= 0;
316 return cAccelEntries
;
323 HACCEL WINAPI
CreateAcceleratorTableA(LPACCEL lpaccl
, int cEntries
)
327 for(i
= 0; i
< cEntries
; ++ i
)
330 NTSTATUS nErrCode
= RtlMultiByteToUnicodeN
332 (PWCHAR
)&lpaccl
[i
].key
,
333 sizeof(lpaccl
[i
].key
),
335 (PCHAR
)&lpaccl
[i
].key
,
336 sizeof(lpaccl
[i
].key
)
339 if(!NT_SUCCESS(nErrCode
)) lpaccl
[i
].key
= -1;
342 return CreateAcceleratorTableW(lpaccl
, cEntries
);
349 int WINAPI
TranslateAcceleratorA(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
356 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
358 Status
= RtlMultiByteToUnicodeN(&wChar
, sizeof(wChar
), NULL
, &cChar
, sizeof(cChar
));
359 if(!NT_SUCCESS(Status
))
361 SetLastError(RtlNtStatusToDosError(Status
));
365 return TranslateAcceleratorW(hWnd
, hAccTable
, &mCopy
);