*
* 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 <noog@libero.it>
* UPDATE HISTORY:
- * 09-05-2001 CSH Created
+ * 09/05/2001 CSH Created
+ * 08/07/2003 KJK Fully implemented
*/
/* INCLUDES ******************************************************************/
-#include <string.h>
#include <windows.h>
-#include <user32.h>
-#include <debug.h>
+#include <user32/accel.h>
+#include <win32k/ntuser.h>
/* FUNCTIONS *****************************************************************/
-int STDCALL
-CopyAcceleratorTableA(HACCEL hAccelSrc,
- LPACCEL lpAccelDst,
- int cAccelEntries)
+/* Lock guarding the cache */
+CRITICAL_SECTION U32AccelCacheLock;
+
+/* Cache */
+U32_ACCEL_CACHE_ENTRY * U32AccelCache = NULL;
+
+/* Look up a handle or resource address in the cache */
+U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE Object, HGLOBAL Data)
{
- return 0;
+ /*
+ 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;
}
-int STDCALL
-CopyAcceleratorTableW(HACCEL hAccelSrc,
- LPACCEL lpAccelDst,
- int cAccelEntries)
+/* Allocate an entry and insert it into the cache */
+void WINAPI U32AccelCacheAdd(HACCEL Object, HGLOBAL Data)
{
- return 0;
+ 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;
}
-HACCEL STDCALL
-CreateAcceleratorTableA(LPACCEL lpaccl,
- int cEntries)
+/* Create an accelerator table from a loaded resource */
+HACCEL WINAPI U32LoadAccelerators(HINSTANCE hInstance, HRSRC hTableRes)
{
- return (HACCEL)0;
+ 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;
}
-HACCEL STDCALL
-CreateAcceleratorTableW(LPACCEL lpaccl,
- int cEntries)
+/* Checks if a message can be translated through an accelerator table */
+BOOL WINAPI U32IsValidAccelMessage(UINT uMsg)
{
- return (HACCEL)0;
+ switch(uMsg)
+ {
+ case WM_KEYDOWN:
+ case WM_CHAR:
+ case WM_SYSKEYDOWN:
+ case WM_SYSCHAR:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
}
-WINBOOL STDCALL
-DestroyAcceleratorTable(HACCEL hAccel)
+/* WIN32 FUNCTIONS ***********************************************************/
+
+/*
+ * Dereference the specified accelerator table, removing it from the cache and
+ * deleting the associated NtUser object as appropriate
+ *
+ * @implemented
+ */
+BOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel)
{
- RtlFreeHeap(RtlGetProcessHeap(), 0, hAccel);
- return(TRUE);
+ 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);
}
-HACCEL STDCALL
-LoadAcceleratorsA(HINSTANCE hInstance,
- LPCSTR lpTableName)
+
+/*
+ * Create an accelerator table from a named resource
+ *
+ * @implemented
+ */
+HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance, LPCWSTR lpTableName)
{
- LPWSTR lpTableNameW;
- HACCEL Res;
- UNICODE_STRING lpTableNameString;
- RtlCreateUnicodeStringFromAsciiz(&lpTableNameString, (LPSTR)lpTableName);
- lpTableNameW = lpTableNameString.Buffer;
- Res = LoadAcceleratorsW(hInstance, lpTableNameW);
- RtlFreeUnicodeString(&lpTableNameString);
- return(Res);
+ return U32LoadAccelerators
+ (
+ hInstance,
+ FindResourceExW(hInstance, MAKEINTRESOURCEW(RT_ACCELERATOR), lpTableName, 0)
+ );
}
-HACCEL STDCALL
-LoadAcceleratorsW(HINSTANCE hInstance,
- LPCWSTR lpTableName)
+
+/*
+ * @implemented
+ */
+HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance, LPCSTR lpTableName)
{
- HRSRC Rsrc;
- HGLOBAL Mem;
- PVOID AccelTableRsrc;
- PVOID AccelTable;
- ULONG Size;
-
- Rsrc = FindResourceW(hInstance, lpTableName, RT_ACCELERATOR);
- if (Rsrc == NULL)
- {
- return(NULL);
- }
- else
+ HRSRC Accel;
+
+ Accel = FindResourceExA(hInstance, MAKEINTRESOURCEA(RT_ACCELERATOR), lpTableName, 0);
+ if (NULL == Accel)
{
- Mem = LoadResource(hInstance, Rsrc);
- Size = SizeofResource(hInstance, Rsrc);
- AccelTableRsrc = LockResource(Mem);
- AccelTable = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
- memcpy(AccelTable, AccelTableRsrc, Size);
- return((HACCEL)AccelTable);
+ return NULL;
}
+
+ return U32LoadAccelerators(hInstance, Accel);
}
-int STDCALL
-TranslateAcceleratorA(HWND hWnd,
- HACCEL hAccTable,
- LPMSG lpMsg)
+/*
+ * Translate a key press into a WM_COMMAND message
+ *
+ * @implemented
+ */
+int WINAPI TranslateAcceleratorW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
{
- return 0;
+ if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
+
+ return NtUserTranslateAccelerator(hWnd, hAccTable, lpMsg);
+}
+
+/*
+ * @implemented
+ */
+int WINAPI CopyAcceleratorTableW
+(
+ HACCEL hAccelSrc,
+ LPACCEL lpAccelDst,
+ int cAccelEntries
+)
+{
+ return NtUserCopyAcceleratorTable(hAccelSrc, lpAccelDst, cAccelEntries);
+}
+
+/*
+ * @implemented
+ */
+HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccl, int cEntries)
+{
+ return NtUserCreateAcceleratorTable(lpaccl, cEntries);
}
-int STDCALL
-TranslateAcceleratorW(HWND hWnd,
- HACCEL hAccTable,
- LPMSG lpMsg)
+
+/*
+ * @implemented
+ */
+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;
+}
+
+
+/*
+ * @implemented
+ */
+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);
+}
+
+
+/*
+ * @implemented
+ */
+int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
+{
+ MSG mCopy = *lpMsg;
+ CHAR cChar;
+ WCHAR wChar;
+ NTSTATUS nErrCode;
+
+ if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
+
+ nErrCode =
+ RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar));
+
+ if(!nErrCode)
+ {
+ SetLastError(RtlNtStatusToDosError(nErrCode));
return 0;
+ }
+
+ return TranslateAcceleratorW(hWnd, hAccTable, &mCopy);
}
+
+/* EOF */