1 /* 2 * ReactOS kernel 3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 4 * 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. 9 * 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. 14 * 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. 18 */ 19 /* 20 * PROJECT: ReactOS user32.dll 21 * FILE: win32ss/user/user32/windows/accel.c 22 * PURPOSE: Accelerator tables 23 * PROGRAMMER: KJK::Hyperion <noog@libero.it> 24 * UPDATE HISTORY: 25 * 09/05/2001 CSH Created 26 * 08/07/2003 KJK Fully implemented 27 */ 28 29 #include <user32.h> 30 31 /* this is the 8 byte accel struct used in Win32 resources (internal only) */ 32 typedef struct 33 { 34 BYTE fVirt; 35 BYTE pad0; 36 WORD key; 37 WORD cmd; 38 WORD pad1; 39 } PE_ACCEL, *LPPE_ACCEL; 40 41 /* Cache entry */ 42 typedef struct _USER_ACCEL_CACHE_ENTRY 43 { 44 struct _USER_ACCEL_CACHE_ENTRY * Next; 45 ULONG_PTR Usage; /* how many times the table has been loaded */ 46 HACCEL Object; /* handle to the NtUser accelerator table object */ 47 HGLOBAL Data; /* base address of the resource data */ 48 } 49 U32_ACCEL_CACHE_ENTRY; 50 51 /* FUNCTIONS *****************************************************************/ 52 53 /* Lock guarding the cache */ 54 CRITICAL_SECTION U32AccelCacheLock; 55 56 /* Cache */ 57 U32_ACCEL_CACHE_ENTRY * U32AccelCache = NULL; 58 59 /* Look up a handle or resource address in the cache */ 60 U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE Object, HGLOBAL Data) 61 { 62 /* 63 to avoid using a double-link list and still allow elements to be removed, 64 return a pointer to the list link that points to the desired entry 65 */ 66 U32_ACCEL_CACHE_ENTRY ** ppEntry = &U32AccelCache; 67 68 for(; *ppEntry; ppEntry = &((*ppEntry)->Next)) 69 if((*ppEntry)->Object == Object || (*ppEntry)->Data == Data) break; 70 71 return ppEntry; 72 } 73 74 /* Allocate an entry and insert it into the cache */ 75 void WINAPI U32AccelCacheAdd(HACCEL Object, HGLOBAL Data) 76 { 77 U32_ACCEL_CACHE_ENTRY * pEntry = 78 LocalAlloc(LMEM_FIXED, sizeof(U32_ACCEL_CACHE_ENTRY)); 79 80 /* failed to allocate an entry - not critical */ 81 if(pEntry == NULL) return; 82 83 /* initialize the entry */ 84 pEntry->Usage = 1; 85 pEntry->Object = Object; 86 pEntry->Data = Data; 87 88 /* insert the entry into the cache */ 89 pEntry->Next = U32AccelCache; 90 U32AccelCache = pEntry; 91 } 92 93 /* Create an accelerator table from a loaded resource */ 94 HACCEL WINAPI U32LoadAccelerators(HINSTANCE hInstance, HRSRC hTableRes) 95 { 96 HGLOBAL hAccTableData; 97 HACCEL hAccTable = NULL; 98 U32_ACCEL_CACHE_ENTRY * pEntry; 99 PE_ACCEL * pAccTableResData; 100 SIZE_T i = 0; 101 SIZE_T j = 0; 102 ACCEL * pAccTableData; 103 104 /* load the accelerator table */ 105 hAccTableData = LoadResource(hInstance, hTableRes); 106 107 /* failure */ 108 if(hAccTableData == NULL) return NULL; 109 110 EnterCriticalSection(&U32AccelCacheLock); 111 112 /* see if this accelerator table has already been loaded */ 113 pEntry = *U32AccelCacheFind(NULL, hAccTableData); 114 115 /* accelerator table already loaded */ 116 if(pEntry) 117 { 118 /* increment the reference count */ 119 ++ pEntry->Usage; 120 121 /* return the existing object */ 122 hAccTable = pEntry->Object; 123 124 /* success */ 125 goto l_Leave; 126 } 127 128 /* determine the number of entries in the table */ 129 i = SizeofResource(hInstance, hTableRes) / sizeof(PE_ACCEL); 130 131 /* allocate the buffer for the table to be passed to Win32K */ 132 pAccTableData = LocalAlloc(LMEM_FIXED, i * sizeof(ACCEL)); 133 134 /* failure */ 135 if(pAccTableData == NULL) goto l_Leave; 136 137 pAccTableResData = (PE_ACCEL *)hAccTableData; 138 139 /* copy the table */ 140 for(j = 0; j < i; ++ j) 141 { 142 pAccTableData[j].fVirt = pAccTableResData[j].fVirt; 143 pAccTableData[j].key = pAccTableResData[j].key; 144 pAccTableData[j].cmd = pAccTableResData[j].cmd; 145 } 146 pAccTableData[i - 1].fVirt |= 0x80; 147 148 /* create a new accelerator table object */ 149 hAccTable = NtUserCreateAcceleratorTable(pAccTableData, i); 150 151 /* free the buffer */ 152 LocalFree(pAccTableData); 153 154 /* failure */ 155 if(hAccTable == NULL) goto l_Leave; 156 157 /* success - cache the object */ 158 U32AccelCacheAdd(hAccTable, pAccTableResData); 159 160 l_Leave: 161 LeaveCriticalSection(&U32AccelCacheLock); 162 return hAccTable; 163 } 164 165 /* Checks if a message can be translated through an accelerator table */ 166 BOOL WINAPI U32IsValidAccelMessage(UINT uMsg) 167 { 168 switch(uMsg) 169 { 170 case WM_KEYDOWN: 171 case WM_KEYUP: 172 case WM_CHAR: 173 case WM_SYSCHAR: 174 case WM_SYSKEYDOWN: 175 case WM_SYSKEYUP: 176 return TRUE; 177 178 default: 179 return FALSE; 180 } 181 } 182 183 /* WIN32 FUNCTIONS ***********************************************************/ 184 185 /* 186 * Dereference the specified accelerator table, removing it from the cache and 187 * deleting the associated NtUser object as appropriate 188 * 189 * @implemented 190 */ 191 BOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel) 192 { 193 U32_ACCEL_CACHE_ENTRY ** ppEntry; 194 ULONG_PTR nUsage = 0; 195 196 if (!hAccel) 197 return FALSE; 198 199 EnterCriticalSection(&U32AccelCacheLock); 200 201 /* see if this accelerator table has been cached */ 202 ppEntry = U32AccelCacheFind(hAccel, NULL); 203 204 /* accelerator table cached */ 205 if(*ppEntry) 206 { 207 U32_ACCEL_CACHE_ENTRY * pEntry = *ppEntry; 208 209 /* decrement the reference count */ 210 nUsage = pEntry->Usage = pEntry->Usage - 1; 211 212 /* reference count now zero: destroy the cache entry */ 213 if(nUsage == 0) 214 { 215 /* unlink the cache entry */ 216 *ppEntry = pEntry->Next; 217 218 /* free the cache entry */ 219 LocalFree(pEntry); 220 } 221 } 222 223 LeaveCriticalSection(&U32AccelCacheLock); 224 225 if(nUsage > 0) return FALSE; 226 227 /* destroy the object */ 228 return NtUserDestroyAcceleratorTable(hAccel); 229 } 230 231 232 /* 233 * Create an accelerator table from a named resource 234 * 235 * @implemented 236 */ 237 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance, LPCWSTR lpTableName) 238 { 239 return U32LoadAccelerators 240 ( 241 hInstance, 242 FindResourceExW(hInstance, (LPCWSTR) RT_ACCELERATOR, lpTableName, 0) 243 ); 244 } 245 246 247 /* 248 * @implemented 249 */ 250 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance, LPCSTR lpTableName) 251 { 252 HRSRC Accel; 253 254 Accel = FindResourceExA(hInstance, (LPCSTR) RT_ACCELERATOR, lpTableName, 0); 255 if (NULL == Accel) 256 { 257 return NULL; 258 } 259 260 return U32LoadAccelerators(hInstance, Accel); 261 } 262 263 /* 264 * Translate a key press into a WM_COMMAND message 265 * 266 * @implemented 267 */ 268 int WINAPI TranslateAcceleratorW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg) 269 { 270 if(!U32IsValidAccelMessage(lpMsg->message)) return 0; 271 272 return NtUserTranslateAccelerator(hWnd, hAccTable, lpMsg); 273 } 274 275 276 /* 277 * @implemented 278 */ 279 int WINAPI CopyAcceleratorTableA 280 ( 281 HACCEL hAccelSrc, 282 LPACCEL lpAccelDst, /* can be NULL */ 283 int cAccelEntries 284 ) 285 { 286 int i; 287 288 cAccelEntries = CopyAcceleratorTableW(hAccelSrc, lpAccelDst, cAccelEntries); 289 290 if (lpAccelDst == NULL) return cAccelEntries; 291 292 for(i = 0; i < cAccelEntries; ++ i) 293 if(!(lpAccelDst[i].fVirt & FVIRTKEY)) 294 { 295 NTSTATUS nErrCode = RtlUnicodeToMultiByteN( 296 (PCHAR)&lpAccelDst[i].key, 297 sizeof(lpAccelDst[i].key), 298 NULL, 299 (PWCHAR)&lpAccelDst[i].key, 300 sizeof(lpAccelDst[i].key) 301 ); 302 303 if(!NT_SUCCESS(nErrCode)) lpAccelDst[i].key = 0; 304 } 305 306 return cAccelEntries; 307 } 308 309 310 /* 311 * @implemented 312 */ 313 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccl, int cEntries) 314 { 315 int i; 316 317 if (!cEntries || !lpaccl) return (HACCEL)0; 318 319 for(i = 0; i < cEntries; ++ i) 320 if(!lpaccl[i].fVirt) 321 { 322 NTSTATUS nErrCode = RtlMultiByteToUnicodeN 323 ( 324 (PWCHAR)&lpaccl[i].key, 325 sizeof(lpaccl[i].key), 326 NULL, 327 (PCHAR)&lpaccl[i].key, 328 sizeof(lpaccl[i].key) 329 ); 330 331 if(!NT_SUCCESS(nErrCode)) lpaccl[i].key = -1; 332 } 333 334 return CreateAcceleratorTableW(lpaccl, cEntries); 335 } 336 337 338 /* 339 * @implemented 340 */ 341 int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg) 342 { 343 switch (lpMsg->message) 344 { 345 case WM_KEYDOWN: 346 case WM_SYSKEYDOWN: 347 return TranslateAcceleratorW( hWnd, hAccTable, lpMsg ); 348 349 case WM_CHAR: 350 case WM_SYSCHAR: 351 { 352 MSG msgW = *lpMsg; 353 char ch = LOWORD(lpMsg->wParam); 354 WCHAR wch; 355 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1); 356 msgW.wParam = MAKEWPARAM(wch, HIWORD(lpMsg->wParam)); 357 return TranslateAcceleratorW( hWnd, hAccTable, &msgW ); 358 } 359 360 default: 361 return 0; 362 } 363 } 364 365 /* EOF */ 366