![]() |
ZenWINX Architecture - Reference Manual - Guides |
|
00001 /* 00002 * ZenWINX - WIndows Native eXtended library. 00003 * Copyright (c) 2007-2010 by Dmitri Arkhangelski (dmitriar@gmail.com). 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 */ 00019 00027 #include "ntndk.h" 00028 #include "zenwinx.h" 00029 00030 char * __stdcall winx_get_error_description(unsigned long status); 00031 00032 #define MAX_NUM_OF_KEYBOARDS 100 00033 00034 typedef struct _KEYBOARD { 00035 int device_number; /* for debugging purposes */ 00036 HANDLE hKbDevice; 00037 HANDLE hKbEvent; 00038 } KEYBOARD, *PKEYBOARD; 00039 00040 KEYBOARD kb[MAX_NUM_OF_KEYBOARDS]; 00041 int number_of_keyboards; 00042 00043 /* prototypes */ 00044 void __stdcall kb_close(void); 00045 int __stdcall kb_check(HANDLE hKbDevice); 00046 int __stdcall kb_open_internal(int device_number); 00047 int __stdcall kb_read_internal(int kb_index,PKEYBOARD_INPUT_DATA pKID,PLARGE_INTEGER pInterval); 00048 00057 int __stdcall kb_open(void) 00058 { 00059 int i, j; 00060 00061 /* initialize kb array */ 00062 memset((void *)kb,0,sizeof(kb)); 00063 number_of_keyboards = 0; 00064 00065 /* check all the keyboards and wait ten seconds 00066 for any keyboard that fails detection. 00067 required for USB devices, which can change ports */ 00068 for(i = 0; i < MAX_NUM_OF_KEYBOARDS; i++) { 00069 if (kb_open_internal(i) == -1) { 00070 if (i < 2) { 00071 winx_printf("Wait 10 seconds for keyboard initialization "); 00072 00073 for(j = 0; j < 10; j++){ 00074 winx_sleep(1000); 00075 winx_printf("."); 00076 } 00077 winx_printf("\n\n"); 00078 00079 (void)kb_open_internal(i); 00080 } 00081 } 00082 } 00083 00084 if(kb[0].hKbDevice) return 0; /* success, at least one keyboard found */ 00085 else return (-1); 00086 } 00087 00092 void __stdcall kb_close(void) 00093 { 00094 int i; 00095 00096 for(i = 0; i < MAX_NUM_OF_KEYBOARDS; i++){ 00097 if(kb[i].hKbDevice == NULL) break; 00098 NtCloseSafe(kb[i].hKbDevice); 00099 NtCloseSafe(kb[i].hKbEvent); 00100 /* don't reset device_number member here */ 00101 number_of_keyboards --; 00102 } 00103 } 00104 00105 #define MAX_LATENCY 100 /* msec */ 00106 00116 int __stdcall kb_read(PKEYBOARD_INPUT_DATA pKID,int msec_timeout) 00117 { 00118 int delay; 00119 int attempts = 0; 00120 LARGE_INTEGER interval; 00121 int i,j; 00122 00123 if(number_of_keyboards == 0) return (-1); 00124 00125 delay = (MAX_LATENCY / number_of_keyboards) + 1; 00126 if(msec_timeout != INFINITE) 00127 attempts = (msec_timeout / MAX_LATENCY) + 1; 00128 interval.QuadPart = -((signed long)delay * 10000); 00129 00130 if(msec_timeout != INFINITE){ 00131 for(i = 0; i < attempts; i++){ 00132 /* loop through all keyboards */ 00133 for(j = 0; j < number_of_keyboards; j++){ 00134 if(kb_read_internal(j,pKID,&interval) >= 0) 00135 return 0; 00136 } 00137 if(number_of_keyboards == 0) return (-1); 00138 } 00139 } else { 00140 while(1){ 00141 /* loop through all keyboards */ 00142 for(j = 0; j < number_of_keyboards; j++){ 00143 if(kb_read_internal(j,pKID,&interval) >= 0) 00144 return 0; 00145 } 00146 if(number_of_keyboards == 0) return (-1); 00147 } 00148 } 00149 return (-1); 00150 } 00151 00152 /* 00153 ************************************************************** 00154 * internal functions * 00155 ************************************************************** 00156 */ 00157 00164 int __stdcall kb_open_internal(int device_number) 00165 { 00166 short device_name[32]; 00167 short event_name[32]; 00168 UNICODE_STRING uStr; 00169 OBJECT_ATTRIBUTES ObjectAttributes; 00170 IO_STATUS_BLOCK IoStatusBlock; 00171 NTSTATUS Status; 00172 HANDLE hKbDevice = NULL; 00173 HANDLE hKbEvent = NULL; 00174 int i; 00175 00176 (void)_snwprintf(device_name,32,L"\\Device\\KeyboardClass%u",device_number); 00177 device_name[31] = 0; 00178 RtlInitUnicodeString(&uStr,device_name); 00179 InitializeObjectAttributes(&ObjectAttributes,&uStr,OBJ_CASE_INSENSITIVE,NULL,NULL); 00180 Status = NtCreateFile(&hKbDevice, 00181 GENERIC_READ | FILE_RESERVE_OPFILTER | FILE_READ_ATTRIBUTES/*0x80100080*/, 00182 &ObjectAttributes,&IoStatusBlock,NULL,FILE_ATTRIBUTE_NORMAL/*0x80*/, 00183 0,FILE_OPEN/*1*/,FILE_DIRECTORY_FILE/*1*/,NULL,0); 00184 if(!NT_SUCCESS(Status)){ 00185 if(device_number < 2){ 00186 DebugPrintEx(Status,"Cannot open the keyboard %ws",device_name); 00187 winx_printf("\nCannot open the keyboard %ws: %x!\n", 00188 device_name,(UINT)Status); 00189 winx_printf("%s\n",winx_get_error_description((ULONG)Status)); 00190 } 00191 return (-1); 00192 } 00193 00194 /* ensure that we have opened a really connected keyboard */ 00195 if(kb_check(hKbDevice) < 0){ 00196 DebugPrintEx(Status,"Invalid keyboard device %ws",device_name); 00197 winx_printf("\nInvalid keyboard device %ws: %x!\n",device_name,(UINT)Status); 00198 winx_printf("%s\n",winx_get_error_description((ULONG)Status)); 00199 NtCloseSafe(hKbDevice); 00200 return (-1); 00201 } 00202 00203 /* create a special event object for internal use */ 00204 (void)_snwprintf(event_name,32,L"\\kb_event%u",device_number); 00205 event_name[31] = 0; 00206 RtlInitUnicodeString(&uStr,event_name); 00207 InitializeObjectAttributes(&ObjectAttributes,&uStr,0,NULL,NULL); 00208 Status = NtCreateEvent(&hKbEvent,STANDARD_RIGHTS_ALL | 0x1ff/*0x1f01ff*/, 00209 &ObjectAttributes,SynchronizationEvent,0/*FALSE*/); 00210 if(!NT_SUCCESS(Status)){ 00211 NtCloseSafe(hKbDevice); 00212 DebugPrintEx(Status,"Cannot create kb_event%u",device_number); 00213 winx_printf("\nCannot create kb_event%u: %x!\n",device_number,(UINT)Status); 00214 winx_printf("%s\n",winx_get_error_description((ULONG)Status)); 00215 return (-1); 00216 } 00217 00218 /* add information to kb array */ 00219 for(i = 0; i < MAX_NUM_OF_KEYBOARDS; i++){ 00220 if(kb[i].hKbDevice == NULL){ 00221 kb[i].hKbDevice = hKbDevice; 00222 kb[i].hKbEvent = hKbEvent; 00223 kb[i].device_number = device_number; 00224 number_of_keyboards ++; 00225 winx_printf("Keyboard device found: %ws.\n",device_name); 00226 return 0; 00227 } 00228 } 00229 00230 winx_printf("\nkb array is full!\n"); 00231 return (-1); 00232 } 00233 00234 #define LIGHTING_REPEAT_COUNT 0x5 00235 00244 int __stdcall kb_light_up_indicators(HANDLE hKbDevice,USHORT LedFlags) 00245 { 00246 NTSTATUS Status; 00247 IO_STATUS_BLOCK iosb; 00248 KEYBOARD_INDICATOR_PARAMETERS kip; 00249 00250 kip.LedFlags = LedFlags; 00251 kip.UnitId = 0; 00252 00253 Status = NtDeviceIoControlFile(hKbDevice,NULL,NULL,NULL, 00254 &iosb,IOCTL_KEYBOARD_SET_INDICATORS, 00255 &kip,sizeof(KEYBOARD_INDICATOR_PARAMETERS),NULL,0); 00256 if(NT_SUCCESS(Status)){ 00257 Status = NtWaitForSingleObject(hKbDevice,FALSE,NULL); 00258 if(NT_SUCCESS(Status)) Status = iosb.Status; 00259 } 00260 if(!NT_SUCCESS(Status) || Status == STATUS_PENDING) return (-1); 00261 00262 return 0; 00263 } 00264 00271 int __stdcall kb_check(HANDLE hKbDevice) 00272 { 00273 USHORT LedFlags; 00274 NTSTATUS Status; 00275 IO_STATUS_BLOCK iosb; 00276 KEYBOARD_INDICATOR_PARAMETERS kip; 00277 int i; 00278 00279 /* try to get LED flags */ 00280 RtlZeroMemory(&kip,sizeof(KEYBOARD_INDICATOR_PARAMETERS)); 00281 Status = NtDeviceIoControlFile(hKbDevice,NULL,NULL,NULL, 00282 &iosb,IOCTL_KEYBOARD_QUERY_INDICATORS,NULL,0, 00283 &kip,sizeof(KEYBOARD_INDICATOR_PARAMETERS)); 00284 if(NT_SUCCESS(Status)){ 00285 Status = NtWaitForSingleObject(hKbDevice,FALSE,NULL); 00286 if(NT_SUCCESS(Status)) Status = iosb.Status; 00287 } 00288 if(!NT_SUCCESS(Status) || Status == STATUS_PENDING) return (-1); 00289 00290 LedFlags = kip.LedFlags; 00291 00292 /* light up LED's */ 00293 for(i = 0; i < LIGHTING_REPEAT_COUNT; i++){ 00294 (void)kb_light_up_indicators(hKbDevice,KEYBOARD_NUM_LOCK_ON); 00295 winx_sleep(100); 00296 (void)kb_light_up_indicators(hKbDevice,KEYBOARD_CAPS_LOCK_ON); 00297 winx_sleep(100); 00298 (void)kb_light_up_indicators(hKbDevice,KEYBOARD_SCROLL_LOCK_ON); 00299 winx_sleep(100); 00300 } 00301 00302 (void)kb_light_up_indicators(hKbDevice,LedFlags); 00303 return 0; 00304 } 00305 00315 int __stdcall kb_read_internal(int kb_index,PKEYBOARD_INPUT_DATA pKID,PLARGE_INTEGER pInterval) 00316 { 00317 LARGE_INTEGER ByteOffset; 00318 IO_STATUS_BLOCK iosb; 00319 NTSTATUS Status; 00320 00321 if(kb[kb_index].hKbDevice == NULL) return (-1); 00322 if(kb[kb_index].hKbEvent == NULL) return (-1); 00323 00324 ByteOffset.QuadPart = 0; 00325 Status = NtReadFile(kb[kb_index].hKbDevice,kb[kb_index].hKbEvent,NULL,NULL, 00326 &iosb,pKID,sizeof(KEYBOARD_INPUT_DATA),&ByteOffset,0); 00327 /* wait in case operation is pending */ 00328 if(NT_SUCCESS(Status)){ 00329 Status = NtWaitForSingleObject(kb[kb_index].hKbEvent,FALSE,pInterval); 00330 if(Status == STATUS_TIMEOUT){ 00331 /* 00332 * If we have timeout we should cancel read operation 00333 * to empty keyboard pending operations queue. 00334 */ 00335 Status = NtCancelIoFile(kb[kb_index].hKbDevice,&iosb); 00336 if(NT_SUCCESS(Status)){ 00337 /* this waiting is very important */ 00338 Status = NtWaitForSingleObject(kb[kb_index].hKbEvent,FALSE,NULL); 00339 if(NT_SUCCESS(Status)) Status = iosb.Status; 00340 } 00341 if(!NT_SUCCESS(Status)){ 00342 /* 00343 * This is a hard error because the next read request 00344 * may destroy stack where pKID pointed data may be allocated. 00345 */ 00346 DebugPrintEx(Status,"NtCancelIoFile for KeyboadClass%u failed", 00347 kb[kb_index].device_number); 00348 winx_printf("\nNtCancelIoFile for KeyboadClass%u failed: %x!\n", 00349 kb[kb_index].device_number,(UINT)Status); 00350 winx_printf("%s\n",winx_get_error_description((ULONG)Status)); 00351 /* Terminate the program! */ 00352 winx_exit(1000); /* exit code is equal to 1000, it was randomly selected :) */ 00353 return (-1); 00354 } 00355 /* Timeout - this is a normal situation. */ 00356 return (-1); 00357 } 00358 if(NT_SUCCESS(Status)) Status = iosb.Status; 00359 } 00360 if(!NT_SUCCESS(Status)){ 00361 DebugPrintEx(Status,"Cannot read the KeyboadClass%u device", 00362 kb[kb_index].device_number); 00363 winx_printf("\nCannot read the KeyboadClass%u device: %x!\n", 00364 kb[kb_index].device_number,(UINT)Status); 00365 winx_printf("%s\n",winx_get_error_description((ULONG)Status)); 00366 return (-1); 00367 } 00368 return 0; 00369 } 00370