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 #include <wine/debug.h>
36 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
44 } PE_ACCEL
, *LPPE_ACCEL
;
46 /* FUNCTIONS *****************************************************************/
48 /* Lock guarding the cache */
49 CRITICAL_SECTION U32AccelCacheLock
;
52 U32_ACCEL_CACHE_ENTRY
* U32AccelCache
= NULL
;
54 /* Look up a handle or resource address in the cache */
55 U32_ACCEL_CACHE_ENTRY
** WINAPI
U32AccelCacheFind(HANDLE Object
, HGLOBAL Data
)
58 to avoid using a double-link list and still allow elements to be removed,
59 return a pointer to the list link that points to the desired entry
61 U32_ACCEL_CACHE_ENTRY
** ppEntry
= &U32AccelCache
;
63 for(; *ppEntry
; ppEntry
= &((*ppEntry
)->Next
))
64 if((*ppEntry
)->Object
== Object
|| (*ppEntry
)->Data
== Data
) break;
69 /* Allocate an entry and insert it into the cache */
70 void WINAPI
U32AccelCacheAdd(HACCEL Object
, HGLOBAL Data
)
72 U32_ACCEL_CACHE_ENTRY
* pEntry
=
73 LocalAlloc(LMEM_FIXED
, sizeof(U32_ACCEL_CACHE_ENTRY
));
75 /* failed to allocate an entry - not critical */
76 if(pEntry
== NULL
) return;
78 /* initialize the entry */
80 pEntry
->Object
= Object
;
83 /* insert the entry into the cache */
84 pEntry
->Next
= U32AccelCache
;
85 U32AccelCache
= pEntry
;
88 /* Create an accelerator table from a loaded resource */
89 HACCEL WINAPI
U32LoadAccelerators(HINSTANCE hInstance
, HRSRC hTableRes
)
91 HGLOBAL hAccTableData
;
92 HACCEL hAccTable
= NULL
;
93 U32_ACCEL_CACHE_ENTRY
* pEntry
;
94 PE_ACCEL
* pAccTableResData
;
97 ACCEL
* pAccTableData
;
99 /* load the accelerator table */
100 hAccTableData
= LoadResource(hInstance
, hTableRes
);
103 if(hAccTableData
== NULL
) return NULL
;
105 EnterCriticalSection(&U32AccelCacheLock
);
107 /* see if this accelerator table has already been loaded */
108 pEntry
= *U32AccelCacheFind(NULL
, hAccTableData
);
110 /* accelerator table already loaded */
113 /* increment the reference count */
116 /* return the existing object */
117 hAccTable
= pEntry
->Object
;
123 /* determine the number of entries in the table */
124 i
= SizeofResource(hInstance
, hTableRes
) / sizeof(PE_ACCEL
);
126 /* allocate the buffer for the table to be passed to Win32K */
127 pAccTableData
= LocalAlloc(LMEM_FIXED
, i
* sizeof(ACCEL
));
130 if(pAccTableData
== NULL
) goto l_Leave
;
132 pAccTableResData
= (PE_ACCEL
*)hAccTableData
;
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
;
141 pAccTableData
[i
- 1].fVirt
|= 0x80;
143 /* create a new accelerator table object */
144 hAccTable
= NtUserCreateAcceleratorTable(pAccTableData
, i
);
146 /* free the buffer */
147 LocalFree(pAccTableData
);
150 if(hAccTable
== NULL
) goto l_Leave
;
152 /* success - cache the object */
153 U32AccelCacheAdd(hAccTable
, pAccTableResData
);
156 LeaveCriticalSection(&U32AccelCacheLock
);
160 /* Checks if a message can be translated through an accelerator table */
161 BOOL WINAPI
U32IsValidAccelMessage(UINT uMsg
)
178 /* WIN32 FUNCTIONS ***********************************************************/
181 * Dereference the specified accelerator table, removing it from the cache and
182 * deleting the associated NtUser object as appropriate
186 BOOL WINAPI
DestroyAcceleratorTable(HACCEL hAccel
)
188 U32_ACCEL_CACHE_ENTRY
** ppEntry
;
189 ULONG_PTR nUsage
= 0;
194 EnterCriticalSection(&U32AccelCacheLock
);
196 /* see if this accelerator table has been cached */
197 ppEntry
= U32AccelCacheFind(hAccel
, NULL
);
199 /* accelerator table cached */
202 U32_ACCEL_CACHE_ENTRY
* pEntry
= *ppEntry
;
204 /* decrement the reference count */
205 nUsage
= pEntry
->Usage
= pEntry
->Usage
- 1;
207 /* reference count now zero: destroy the cache entry */
210 /* unlink the cache entry */
211 *ppEntry
= pEntry
->Next
;
213 /* free the cache entry */
218 LeaveCriticalSection(&U32AccelCacheLock
);
220 if(nUsage
> 0) return FALSE
;
222 /* destroy the object */
223 return NtUserDestroyAcceleratorTable(hAccel
);
228 * Create an accelerator table from a named resource
232 HACCEL WINAPI
LoadAcceleratorsW(HINSTANCE hInstance
, LPCWSTR lpTableName
)
234 return U32LoadAccelerators
237 FindResourceExW(hInstance
, (LPCWSTR
) RT_ACCELERATOR
, lpTableName
, 0)
245 HACCEL WINAPI
LoadAcceleratorsA(HINSTANCE hInstance
, LPCSTR lpTableName
)
249 Accel
= FindResourceExA(hInstance
, (LPCSTR
) RT_ACCELERATOR
, lpTableName
, 0);
255 return U32LoadAccelerators(hInstance
, Accel
);
259 * Translate a key press into a WM_COMMAND message
263 int WINAPI
TranslateAcceleratorW(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
265 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
267 return NtUserTranslateAccelerator(hWnd
, hAccTable
, lpMsg
);
274 int WINAPI CopyAcceleratorTableA
277 LPACCEL lpAccelDst
, /* can be NULL */
283 cAccelEntries
= CopyAcceleratorTableW(hAccelSrc
, lpAccelDst
, cAccelEntries
);
285 if (lpAccelDst
== NULL
) return cAccelEntries
;
287 for(i
= 0; i
< cAccelEntries
; ++ i
)
288 if(!(lpAccelDst
[i
].fVirt
& FVIRTKEY
))
290 NTSTATUS nErrCode
= RtlUnicodeToMultiByteN(
291 (PCHAR
)&lpAccelDst
[i
].key
,
292 sizeof(lpAccelDst
[i
].key
),
294 (PWCHAR
)&lpAccelDst
[i
].key
,
295 sizeof(lpAccelDst
[i
].key
)
298 if(!NT_SUCCESS(nErrCode
)) lpAccelDst
[i
].key
= 0;
301 return cAccelEntries
;
308 HACCEL WINAPI
CreateAcceleratorTableA(LPACCEL lpaccl
, int cEntries
)
312 if (!cEntries
|| !lpaccl
) return (HACCEL
)0;
314 for(i
= 0; i
< cEntries
; ++ i
)
317 NTSTATUS nErrCode
= RtlMultiByteToUnicodeN
319 (PWCHAR
)&lpaccl
[i
].key
,
320 sizeof(lpaccl
[i
].key
),
322 (PCHAR
)&lpaccl
[i
].key
,
323 sizeof(lpaccl
[i
].key
)
326 if(!NT_SUCCESS(nErrCode
)) lpaccl
[i
].key
= -1;
329 return CreateAcceleratorTableW(lpaccl
, cEntries
);
336 int WINAPI
TranslateAcceleratorA(HWND hWnd
, HACCEL hAccTable
, LPMSG lpMsg
)
343 if(!U32IsValidAccelMessage(lpMsg
->message
)) return 0;
345 Status
= RtlMultiByteToUnicodeN(&wChar
, sizeof(wChar
), NULL
, &cChar
, sizeof(cChar
));
346 if(!NT_SUCCESS(Status
))
348 SetLastError(RtlNtStatusToDosError(Status
));
352 return TranslateAcceleratorW(hWnd
, hAccTable
, &mCopy
);