diff --git a/reactos/lib/user32/windows/accel.c b/reactos/lib/user32/windows/accel.c index 5eb06d73123..380d4c6c92d 100644 --- a/reactos/lib/user32/windows/accel.c +++ b/reactos/lib/user32/windows/accel.c @@ -16,14 +16,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: accel.c,v 1.6 2003/05/12 19:30:00 jfilby Exp $ +/* $Id: accel.c,v 1.7 2003/07/09 00:09:47 hyperion Exp $ * * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/input.c - * PURPOSE: Input - * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * PURPOSE: Accelerator tables + * PROGRAMMER: KJK::Hyperion * UPDATE HISTORY: - * 09-05-2001 CSH Created + * 09/05/2001 CSH Created + * 08/07/2003 KJK Fully implemented */ /* INCLUDES ******************************************************************/ @@ -34,101 +35,325 @@ /* FUNCTIONS *****************************************************************/ -int STDCALL -CopyAcceleratorTableA(HACCEL hAccelSrc, - LPACCEL lpAccelDst, - int cAccelEntries) +/* RT_ACCELERATOR resources are arrays of RES_ACCEL structures */ +typedef struct _RES_ACCEL { - UNIMPLEMENTED; + WORD fVirt; + WORD key; + DWORD cmd; +} +RES_ACCEL; + +/* ACCELERATOR TABLES CACHE */ +/* Cache entry */ +typedef struct _USER_ACCEL_CACHE_ENTRY +{ + struct _USER_ACCEL_CACHE_ENTRY * Next; + ULONG_PTR Usage; /* how many times the table has been loaded */ + HACCEL Object; /* handle to the NtUser accelerator table object */ + HGLOBAL Data; /* base address of the resource data */ +} +U32_ACCEL_CACHE_ENTRY; + +/* Lock guarding the cache */ +CRITICAL_SECTION U32AccelCacheLock; + +/* Cache */ +U32_ACCEL_CACHE_ENTRY * U32AccelCache = NULL; + +U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE, HGLOBAL); +void WINAPI U32AccelCacheAdd(HACCEL, HGLOBAL); + +/* Look up a handle or resource address in the cache */ +U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE Object, HGLOBAL Data) +{ + /* + to avoid using a double-link list and still allow elements to be removed, + return a pointer to the list link that points to the desired entry + */ + U32_ACCEL_CACHE_ENTRY ** ppEntry = &U32AccelCache; + + for(; *ppEntry; ppEntry = &((*ppEntry)->Next)) + if((*ppEntry)->Object == Object || (*ppEntry)->Data == Data) break; + + return ppEntry; +} + +/* Allocate an entry and insert it into the cache */ +void WINAPI U32AccelCacheAdd(HACCEL Object, HGLOBAL Data) +{ + U32_ACCEL_CACHE_ENTRY * pEntry = + LocalAlloc(LMEM_FIXED, sizeof(U32_ACCEL_CACHE_ENTRY)); + + /* failed to allocate an entry - not critical */ + if(pEntry == NULL) return; + + /* initialize the entry */ + pEntry->Usage = 1; + pEntry->Object = Object; + pEntry->Data = Data; + + /* insert the entry into the cache */ + pEntry->Next = U32AccelCache; + U32AccelCache = pEntry; +} + +/* Create an accelerator table from a loaded resource */ +HACCEL WINAPI U32LoadAccelerators(HINSTANCE hInstance, HRSRC hTableRes) +{ + HGLOBAL hAccTableData; + HACCEL hAccTable = NULL; + U32_ACCEL_CACHE_ENTRY * pEntry; + RES_ACCEL * pAccTableResData; + RES_ACCEL * p; + SIZE_T i = 0; + SIZE_T j = 0; + ACCEL * pAccTableData; + + /* load the accelerator table */ + hAccTableData = LoadResource(hInstance, hTableRes); + + /* failure */ + if(hAccTableData == NULL) return NULL; + + RtlEnterCriticalSection(&U32AccelCacheLock); + + /* see if this accelerator table has already been loaded */ + pEntry = *U32AccelCacheFind(NULL, hAccTableData); + + /* accelerator table already loaded */ + if(pEntry) + { + /* increment the reference count */ + ++ pEntry->Usage; + + /* return the existing object */ + hAccTable = pEntry->Object; + + /* success */ + goto l_Leave; + } + + /* count the number of entries in the table */ + p = pAccTableResData = (RES_ACCEL *)hAccTableData; + + while(1) + { + /* FIXME??? unknown flag 0x60 stops the scan */ + if(p->fVirt & 0x60) break; + + ++ i; + ++ p; + + /* flag 0x80 marks the last entry of the table */ + if(p->fVirt & 0x80) break; + } + + /* allocate the buffer for the table to be passed to Win32K */ + pAccTableData = LocalAlloc(LMEM_FIXED, i * sizeof(ACCEL)); + + /* failure */ + if(pAccTableData == NULL) goto l_Leave; + + /* copy the table */ + for(j = 0; j < i; ++ j) + { + pAccTableData[j].fVirt = pAccTableResData[j].fVirt; + pAccTableData[j].key = pAccTableResData[j].key; + pAccTableData[j].cmd = pAccTableResData[j].cmd; + } + + /* create a new accelerator table object */ + hAccTable = NtUserCreateAcceleratorTable(pAccTableData, i); + + /* free the buffer */ + LocalFree(pAccTableData); + + /* failure */ + if(hAccTable == NULL) goto l_Leave; + + /* success - cache the object */ + U32AccelCacheAdd(hAccTable, pAccTableResData); + +l_Leave: + RtlLeaveCriticalSection(&U32AccelCacheLock); + return hAccTable; +} + +/* Checks if a message can be translated through an accelerator table */ +BOOL WINAPI U32IsValidAccelMessage(UINT uMsg) +{ + switch(uMsg) + { + case WM_KEYDOWN: + case WM_CHAR: + case WM_SYSKEYDOWN: + case WM_SYSCHAR: + return TRUE; + + default: + return FALSE; + } +} + +/* WIN32 FUNCTIONS ***********************************************************/ + +/* + Dereference the specified accelerator table, removing it from the cache and + deleting the associated NtUser object as appropriate +*/ +BOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel) +{ + U32_ACCEL_CACHE_ENTRY ** ppEntry; + ULONG_PTR nUsage = 0; + + RtlEnterCriticalSection(&U32AccelCacheLock); + + /* see if this accelerator table has been cached */ + ppEntry = U32AccelCacheFind(hAccel, NULL); + + /* accelerator table cached */ + if(*ppEntry) + { + U32_ACCEL_CACHE_ENTRY * pEntry = *ppEntry; + + /* decrement the reference count */ + nUsage = pEntry->Usage= pEntry->Usage - 1; + + /* reference count now zero: destroy the cache entry */ + if(nUsage == 0) + { + /* unlink the cache entry */ + *ppEntry = pEntry->Next; + + /* free the cache entry */ + LocalFree(pEntry); + } + } + + RtlLeaveCriticalSection(&U32AccelCacheLock); + + if(nUsage > 0) return FALSE; + + /* destroy the object */ + return NtUserDestroyAcceleratorTable(hAccel); +} + +/* Create an accelerator table from a named resource */ +HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance, LPCWSTR lpTableName) +{ + return U32LoadAccelerators + ( + hInstance, + FindResourceExW(hInstance, MAKEINTRESOURCEW(RT_ACCELERATOR), lpTableName, 0) + ); +} + +HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance, LPCSTR lpTableName) +{ + return U32LoadAccelerators + ( + hInstance, + FindResourceExA(hInstance, MAKEINTRESOURCEA(RT_ACCELERATOR), lpTableName, 0) + ); +} + +/* Translate a key press into a WM_COMMAND message */ +int WINAPI TranslateAcceleratorW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg) +{ + if(!U32IsValidAccelMessage(lpMsg->message)) return 0; + + return NtUserTranslateAccelerator(hWnd, hAccTable, lpMsg); +} + +/* NTUSER STUBS */ +int WINAPI CopyAcceleratorTableW +( + HACCEL hAccelSrc, + LPACCEL lpAccelDst, + int cAccelEntries +) +{ + return NtUserCopyAcceleratorTable(hAccelSrc, lpAccelDst, cAccelEntries); +} + +HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccl, int cEntries) +{ + return NtUserCreateAcceleratorTable(lpaccl, cEntries); +} + +/* ANSI STUBS */ +int WINAPI CopyAcceleratorTableA +( + HACCEL hAccelSrc, + LPACCEL lpAccelDst, + int cAccelEntries +) +{ + int i; + + cAccelEntries = CopyAcceleratorTableW(hAccelSrc, lpAccelDst, cAccelEntries); + + if(cAccelEntries == 0) return 0; + + for(i = 0; i < cAccelEntries; ++ i) + if(!(lpAccelDst[i].fVirt & FVIRTKEY)) + { + NTSTATUS nErrCode = RtlUnicodeToMultiByteN + ( + (PCHAR)&lpAccelDst[i].key, + sizeof(lpAccelDst[i].key), + NULL, + (PWCHAR)&lpAccelDst[i].key, + sizeof(lpAccelDst[i].key) + ); + + if(!NT_SUCCESS(nErrCode)) lpAccelDst[i].key = 0; + } + + return cAccelEntries; +} + +HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccl, int cEntries) +{ + int i; + + for(i = 0; i < cEntries; ++ i) + if(!lpaccl[i].fVirt) + { + NTSTATUS nErrCode = RtlMultiByteToUnicodeN + ( + (PWCHAR)&lpaccl[i].key, + sizeof(lpaccl[i].key), + NULL, + (PCHAR)&lpaccl[i].key, + sizeof(lpaccl[i].key) + ); + + if(!NT_SUCCESS(nErrCode)) lpaccl[i].key = -1; + } + + return CreateAcceleratorTableW(lpaccl, cEntries); +} + +int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg) +{ + MSG mCopy = *lpMsg; + CHAR cChar; + WCHAR wChar; + + if(!U32IsValidAccelMessage(lpMsg->message)) return 0; + + NTSTATUS nErrCode = + RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar)); + + if(!nErrCode) + { + SetLastError(RtlNtStatusToDosError(nErrCode)); return 0; + } + + return TranslateAcceleratorW(hWnd, hAccTable, &mCopy); } -int STDCALL -CopyAcceleratorTableW(HACCEL hAccelSrc, - LPACCEL lpAccelDst, - int cAccelEntries) -{ - UNIMPLEMENTED; - return 0; -} - -HACCEL STDCALL -CreateAcceleratorTableA(LPACCEL lpaccl, - int cEntries) -{ - UNIMPLEMENTED; - return (HACCEL)0; -} - -HACCEL STDCALL -CreateAcceleratorTableW(LPACCEL lpaccl, - int cEntries) -{ - UNIMPLEMENTED; - return (HACCEL)0; -} - -WINBOOL STDCALL -DestroyAcceleratorTable(HACCEL hAccel) -{ - RtlFreeHeap(RtlGetProcessHeap(), 0, hAccel); - return(TRUE); -} - -HACCEL STDCALL -LoadAcceleratorsA(HINSTANCE hInstance, - LPCSTR lpTableName) -{ - LPWSTR lpTableNameW; - HACCEL Res; - UNICODE_STRING lpTableNameString; - RtlCreateUnicodeStringFromAsciiz(&lpTableNameString, (LPSTR)lpTableName); - lpTableNameW = lpTableNameString.Buffer; - Res = LoadAcceleratorsW(hInstance, lpTableNameW); - RtlFreeUnicodeString(&lpTableNameString); - return(Res); -} - -HACCEL STDCALL -LoadAcceleratorsW(HINSTANCE hInstance, - LPCWSTR lpTableName) -{ - HRSRC Rsrc; - HGLOBAL Mem; - PVOID AccelTableRsrc; - PVOID AccelTable; - ULONG Size; - - Rsrc = FindResourceW(hInstance, lpTableName, RT_ACCELERATOR); - if (Rsrc == NULL) - { - return(NULL); - } - else - { - Mem = LoadResource(hInstance, Rsrc); - Size = SizeofResource(hInstance, Rsrc); - AccelTableRsrc = LockResource(Mem); - AccelTable = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); - memcpy(AccelTable, AccelTableRsrc, Size); - return((HACCEL)AccelTable); - } -} - -int STDCALL -TranslateAcceleratorA(HWND hWnd, - HACCEL hAccTable, - LPMSG lpMsg) -{ - UNIMPLEMENTED; - return 0; -} - -int STDCALL -TranslateAcceleratorW(HWND hWnd, - HACCEL hAccTable, - LPMSG lpMsg) -{ - UNIMPLEMENTED; - return 0; -} +/* EOF */