1 /* 2 * PROJECT: ReactOS HID Parser Library 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: lib/drivers/hidparser/api.c 5 * PURPOSE: HID Parser 6 * PROGRAMMERS: 7 * Michael Martin (michael.martin@reactos.org) 8 * Johannes Anderwald (johannes.anderwald@reactos.org) 9 */ 10 11 #include "parser.h" 12 13 #define NDEBUG 14 #include <debug.h> 15 16 static ULONG KeyboardScanCodes[256] = 17 { /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 18 /* 0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, 0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 19 /* 1 */ 0x0032, 0x0031, 0x0018, 0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, 0x002d, 0x0015, 0x002c, 0x0002, 0x0003, 20 /* 2 */ 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x001c, 0x0001, 0x000e, 0x000f, 0x0039, 0x000c, 0x000d, 0x001a, 21 /* 3 */ 0x001b, 0x002b, 0x002b, 0x0027, 0x0028, 0x0029, 0x0033, 0x0034, 0x0035, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 22 /* 4 */ 0x0041, 0x0042, 0x0043, 0x0044, 0x0057, 0x0058, 0xE037, 0x0046, 0x0045, 0xE052, 0xE047, 0xE049, 0xE053, 0xE04F, 0xE051, 0xE04D, 23 /* 5 */ 0xE04B, 0xE050, 0xE048, 0x0045, 0xE035, 0x0037, 0x004a, 0x004e, 0xE01C, 0x004f, 0x0050, 0x0051, 0x004b, 0x004c, 0x004d, 0x0047, 24 /* 6 */ 0x0048, 0x0049, 0x0052, 0x0053, 0x0056, 0xE05D, 0xE05E, 0x0075, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 25 /* 7 */ 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x0086, 0x008a, 0x0082, 0x0084, 0x0080, 0x0081, 0x0083, 0x0089, 0x0085, 0x0087, 0x0088, 0x0071, 26 /* 8 */ 0x0073, 0x0072, 0x0000, 0x0000, 0x0000, 0x0079, 0x0000, 0x0059, 0x005d, 0x007c, 0x005c, 0x005e, 0x005f, 0x0000, 0x0000, 0x0000, 27 /* 9 */ 0x007a, 0x007b, 0x005a, 0x005b, 0x0055, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 28 /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 29 /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 30 /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 31 /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 32 /* E */ 0x001D, 0x002A, 0x0038, 0xE05B, 0xE01D, 0x0036, 0xE038, 0xE05C, 0x00a4, 0x00a6, 0x00a5, 0x00a3, 0x00a1, 0x0073, 0x0072, 0x0071, 33 /* F */ 0x0096, 0x009e, 0x009f, 0x0080, 0x0088, 0x00b1, 0x00b2, 0x00b0, 0x008e, 0x0098, 0x00ad, 0x008c, 0x0000, 0x0000, 0x0000, 0x0000, 34 }; 35 36 static struct 37 { 38 USAGE Usage; 39 ULONG ScanCode; 40 } CustomerScanCodes[] = 41 { 42 { 0x00B5, 0xE019 }, 43 { 0x00B6, 0xE010 }, 44 { 0x00B7, 0xE024 }, 45 { 0x00CD, 0xE022 }, 46 { 0x00E2, 0xE020 }, 47 { 0x00E9, 0xE030 }, 48 { 0x00EA, 0xE02E }, 49 { 0x0183, 0xE06D }, 50 { 0x018A, 0xE06C }, 51 { 0x0192, 0xE021 }, 52 { 0x0194, 0xE06B }, 53 { 0x0221, 0xE065 }, 54 { 0x0223, 0xE032 }, 55 { 0x0224, 0xE06A }, 56 { 0x0225, 0xE069 }, 57 { 0x0226, 0xE068 }, 58 { 0x0227, 0xE067 }, 59 { 0x022A, 0xE066 }, 60 }; 61 62 #define NTOHS(n) (((((unsigned short)(n) & 0xFF)) << 8) | (((unsigned short)(n) & 0xFF00) >> 8)) 63 64 NTSTATUS 65 HidParser_GetCollectionUsagePage( 66 IN PVOID CollectionContext, 67 OUT PUSHORT Usage, 68 OUT PUSHORT UsagePage) 69 { 70 PHID_COLLECTION Collection; 71 72 // 73 // find collection 74 // 75 Collection = HidParser_GetCollectionFromContext(CollectionContext); 76 if (!Collection) 77 { 78 // 79 // collection not found 80 // 81 return HIDP_STATUS_USAGE_NOT_FOUND; 82 } 83 84 // 85 // store result 86 // 87 *UsagePage = (Collection->Usage >> 16); 88 *Usage = (Collection->Usage & 0xFFFF); 89 return HIDP_STATUS_SUCCESS; 90 } 91 92 ULONG 93 HidParser_GetReportLength( 94 IN PVOID CollectionContext, 95 IN UCHAR ReportType) 96 { 97 PHID_REPORT Report; 98 ULONG ReportLength; 99 100 // 101 // get first report 102 // 103 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 104 if (!Report) 105 { 106 // 107 // no report found 108 // 109 return 0; 110 } 111 112 // 113 // get report length 114 // 115 ReportLength = Report->ReportSize; 116 117 // 118 // done 119 // 120 if (ReportLength) 121 { 122 // 123 // byte aligned length 124 // 125 ASSERT(ReportLength % 8 == 0); 126 return ReportLength / 8; 127 } 128 return ReportLength; 129 } 130 131 ULONG 132 HidParser_GetReportItemCountFromReportType( 133 IN PVOID CollectionContext, 134 IN UCHAR ReportType) 135 { 136 PHID_REPORT Report; 137 138 // 139 // get report 140 // 141 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 142 if (!Report) 143 { 144 // 145 // no such report 146 // 147 return 0; 148 } 149 150 // 151 // return report item count 152 // 153 return Report->ItemCount; 154 } 155 156 157 ULONG 158 HidParser_GetReportItemTypeCountFromReportType( 159 IN PVOID CollectionContext, 160 IN UCHAR ReportType, 161 IN ULONG bData) 162 { 163 ULONG Index; 164 PHID_REPORT Report; 165 ULONG ItemCount = 0; 166 167 // 168 // get report 169 // 170 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 171 if (!Report) 172 { 173 // 174 // no such report 175 // 176 return 0; 177 } 178 179 // 180 // enumerate all items 181 // 182 for(Index = 0; Index < Report->ItemCount; Index++) 183 { 184 // 185 // check item type 186 // 187 if (Report->Items[Index].HasData && bData) 188 { 189 // 190 // found data item 191 // 192 ItemCount++; 193 } 194 else if (Report->Items[Index].HasData == FALSE && bData == FALSE) 195 { 196 // 197 // found value item 198 // 199 ItemCount++; 200 } 201 } 202 203 // 204 // no report items 205 // 206 return ItemCount; 207 } 208 209 ULONG 210 HidParser_GetMaxUsageListLengthWithReportAndPage( 211 IN PVOID CollectionContext, 212 IN UCHAR ReportType, 213 IN USAGE UsagePage OPTIONAL) 214 { 215 ULONG Index; 216 PHID_REPORT Report; 217 ULONG ItemCount = 0; 218 USHORT CurrentUsagePage; 219 220 // 221 // get report 222 // 223 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 224 if (!Report) 225 { 226 // 227 // no such report 228 // 229 return 0; 230 } 231 232 for(Index = 0; Index < Report->ItemCount; Index++) 233 { 234 // 235 // check usage page 236 // 237 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16); 238 if (CurrentUsagePage == UsagePage && Report->Items[Index].HasData) 239 { 240 // 241 // found item 242 // 243 ItemCount++; 244 } 245 } 246 247 // 248 // done 249 // 250 return ItemCount; 251 } 252 253 NTSTATUS 254 HidParser_GetSpecificValueCapsWithReport( 255 IN PVOID CollectionContext, 256 IN UCHAR ReportType, 257 IN USHORT UsagePage, 258 IN USHORT Usage, 259 OUT PHIDP_VALUE_CAPS ValueCaps, 260 IN OUT PUSHORT ValueCapsLength) 261 { 262 ULONG Index; 263 PHID_REPORT Report; 264 USHORT ItemCount = 0; 265 USHORT CurrentUsagePage; 266 USHORT CurrentUsage; 267 268 // 269 // get report 270 // 271 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 272 if (!Report) 273 { 274 // 275 // no such report 276 // 277 return HIDP_STATUS_REPORT_DOES_NOT_EXIST; 278 } 279 280 for(Index = 0; Index < Report->ItemCount; Index++) 281 { 282 // 283 // check usage page 284 // 285 CurrentUsagePage = (Report->Items[Index].UsageMinimum >> 16); 286 CurrentUsage = (Report->Items[Index].UsageMinimum & 0xFFFF); 287 288 if ((Usage == CurrentUsage && UsagePage == CurrentUsagePage) || (Usage == 0 && UsagePage == CurrentUsagePage) || (Usage == CurrentUsage && UsagePage == 0) || (Usage == 0 && UsagePage == 0)) 289 { 290 // 291 // check if there is enough place for the caps 292 // 293 if (ItemCount < *ValueCapsLength) 294 { 295 // 296 // zero caps 297 // 298 ZeroFunction(&ValueCaps[ItemCount], sizeof(HIDP_VALUE_CAPS)); 299 300 // 301 // init caps 302 // 303 ValueCaps[ItemCount].UsagePage = CurrentUsagePage; 304 ValueCaps[ItemCount].ReportID = Report->ReportID; 305 ValueCaps[ItemCount].LogicalMin = Report->Items[Index].Minimum; 306 ValueCaps[ItemCount].LogicalMax = Report->Items[Index].Maximum; 307 ValueCaps[ItemCount].IsAbsolute = !Report->Items[Index].Relative; 308 ValueCaps[ItemCount].BitSize = Report->Items[Index].BitCount; 309 310 // 311 // FIXME: FILLMEIN 312 // 313 } 314 315 316 // 317 // found item 318 // 319 ItemCount++; 320 } 321 } 322 323 // 324 // store result 325 // 326 *ValueCapsLength = ItemCount; 327 328 if (ItemCount) 329 { 330 // 331 // success 332 // 333 return HIDP_STATUS_SUCCESS; 334 } 335 336 // 337 // item not found 338 // 339 return HIDP_STATUS_USAGE_NOT_FOUND; 340 } 341 342 NTSTATUS 343 HidParser_GetUsagesWithReport( 344 IN PVOID CollectionContext, 345 IN UCHAR ReportType, 346 IN USAGE UsagePage, 347 OUT USAGE *UsageList, 348 IN OUT PULONG UsageLength, 349 IN PCHAR ReportDescriptor, 350 IN ULONG ReportDescriptorLength) 351 { 352 ULONG Index; 353 PHID_REPORT Report; 354 ULONG ItemCount = 0; 355 USHORT CurrentUsagePage; 356 PHID_REPORT_ITEM ReportItem; 357 UCHAR Activated; 358 ULONG Data; 359 PUSAGE_AND_PAGE UsageAndPage = NULL; 360 361 // 362 // get report 363 // 364 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 365 if (!Report) 366 { 367 // 368 // no such report 369 // 370 return HIDP_STATUS_REPORT_DOES_NOT_EXIST; 371 } 372 373 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1)) 374 { 375 // 376 // invalid report descriptor length 377 // 378 return HIDP_STATUS_INVALID_REPORT_LENGTH; 379 } 380 381 // 382 // cast to usage and page 383 // 384 if (UsagePage == HID_USAGE_PAGE_UNDEFINED) 385 { 386 // 387 // the caller requested any set usages 388 // 389 UsageAndPage = (PUSAGE_AND_PAGE)UsageList; 390 } 391 392 for(Index = 0; Index < Report->ItemCount; Index++) 393 { 394 // 395 // get report item 396 // 397 ReportItem = &Report->Items[Index]; 398 399 // 400 // does it have data 401 // 402 if (!ReportItem->HasData) 403 continue; 404 405 // 406 // check usage page 407 // 408 CurrentUsagePage = (ReportItem->UsageMinimum >> 16); 409 410 if (UsagePage != HID_USAGE_PAGE_UNDEFINED) 411 { 412 // 413 // does usage match 414 // 415 if (UsagePage != CurrentUsagePage) 416 continue; 417 } 418 419 // 420 // check if the specified usage is activated 421 // 422 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength); 423 ASSERT(ReportItem->BitCount <= 8); 424 425 // 426 // one extra shift for skipping the prepended report id 427 // 428 Data = ReportDescriptor[ReportItem->ByteOffset + 1]; 429 430 // 431 // shift data 432 // 433 Data >>= ReportItem->Shift; 434 435 // 436 // clear unwanted bits 437 // 438 Data &= ReportItem->Mask; 439 440 // 441 // is it activated 442 // 443 Activated = (Data != 0); 444 445 if (!Activated) 446 continue; 447 448 // 449 // is there enough space for the usage 450 // 451 if (ItemCount >= *UsageLength) 452 { 453 ItemCount++; 454 continue; 455 } 456 457 if (UsagePage != HID_USAGE_PAGE_UNDEFINED) 458 { 459 // 460 // store item 461 // 462 UsageList[ItemCount] = (ReportItem->UsageMinimum & 0xFFFF); 463 } 464 else 465 { 466 // 467 // store usage and page 468 // 469 if (ReportItem->BitCount == 1) 470 { 471 // 472 // use usage minimum 473 // 474 UsageAndPage[ItemCount].Usage =(ReportItem->UsageMinimum & 0xFFFF); 475 } 476 else 477 { 478 // 479 // use value from control 480 // 481 UsageAndPage[ItemCount].Usage = (USHORT)Data; 482 } 483 UsageAndPage[ItemCount].UsagePage = CurrentUsagePage; 484 } 485 ItemCount++; 486 } 487 488 if (ItemCount > *UsageLength) 489 { 490 // 491 // list too small 492 // 493 return HIDP_STATUS_BUFFER_TOO_SMALL; 494 } 495 496 if (UsagePage == HID_USAGE_PAGE_UNDEFINED) 497 { 498 // 499 // success, clear rest of array 500 // 501 ZeroFunction(&UsageAndPage[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE_AND_PAGE)); 502 } 503 else 504 { 505 // 506 // success, clear rest of array 507 // 508 ZeroFunction(&UsageList[ItemCount], (*UsageLength - ItemCount) * sizeof(USAGE)); 509 } 510 511 512 // 513 // store result size 514 // 515 *UsageLength = ItemCount; 516 517 // 518 // done 519 // 520 return HIDP_STATUS_SUCCESS; 521 } 522 523 ULONG 524 HidParser_UsesReportId( 525 IN PVOID CollectionContext, 526 IN UCHAR ReportType) 527 { 528 PHID_REPORT Report; 529 530 // 531 // get report 532 // 533 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 534 if (!Report) 535 { 536 // 537 // no such report 538 // 539 return 0; 540 } 541 542 // 543 // returns true when report id != 0 544 // 545 return (Report->ReportID != 0); 546 547 } 548 549 NTSTATUS 550 HidParser_GetUsageValueWithReport( 551 IN PVOID CollectionContext, 552 IN UCHAR ReportType, 553 IN USAGE UsagePage, 554 IN USAGE Usage, 555 OUT PULONG UsageValue, 556 IN PCHAR ReportDescriptor, 557 IN ULONG ReportDescriptorLength) 558 { 559 ULONG Index; 560 PHID_REPORT Report; 561 USHORT CurrentUsagePage; 562 PHID_REPORT_ITEM ReportItem; 563 ULONG Data; 564 565 // 566 // get report 567 // 568 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 569 if (!Report) 570 { 571 // 572 // no such report 573 // 574 return HIDP_STATUS_REPORT_DOES_NOT_EXIST; 575 } 576 577 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1)) 578 { 579 // 580 // invalid report descriptor length 581 // 582 return HIDP_STATUS_INVALID_REPORT_LENGTH; 583 } 584 585 for (Index = 0; Index < Report->ItemCount; Index++) 586 { 587 // 588 // get report item 589 // 590 ReportItem = &Report->Items[Index]; 591 592 // 593 // check usage page 594 // 595 CurrentUsagePage = (ReportItem->UsageMinimum >> 16); 596 597 // 598 // does usage page match 599 // 600 if (UsagePage != CurrentUsagePage) 601 continue; 602 603 // 604 // does the usage match 605 // 606 if (Usage != (ReportItem->UsageMinimum & 0xFFFF)) 607 continue; 608 609 // 610 // check if the specified usage is activated 611 // 612 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength); 613 614 // 615 // one extra shift for skipping the prepended report id 616 // 617 Data = 0; 618 CopyFunction(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1))); 619 620 // 621 // shift data 622 // 623 Data >>= ReportItem->Shift; 624 625 // 626 // clear unwanted bits 627 // 628 Data &= ReportItem->Mask; 629 630 // 631 // store result 632 // 633 *UsageValue = Data; 634 return HIDP_STATUS_SUCCESS; 635 } 636 637 // 638 // usage not found 639 // 640 return HIDP_STATUS_USAGE_NOT_FOUND; 641 } 642 643 644 645 NTSTATUS 646 HidParser_GetScaledUsageValueWithReport( 647 IN PVOID CollectionContext, 648 IN UCHAR ReportType, 649 IN USAGE UsagePage, 650 IN USAGE Usage, 651 OUT PLONG UsageValue, 652 IN PCHAR ReportDescriptor, 653 IN ULONG ReportDescriptorLength) 654 { 655 ULONG Index; 656 PHID_REPORT Report; 657 USHORT CurrentUsagePage; 658 PHID_REPORT_ITEM ReportItem; 659 ULONG Data; 660 661 // 662 // get report 663 // 664 Report = HidParser_GetReportInCollection(CollectionContext, ReportType); 665 if (!Report) 666 { 667 // 668 // no such report 669 // 670 return HIDP_STATUS_REPORT_DOES_NOT_EXIST; 671 } 672 673 if (Report->ReportSize / 8 != (ReportDescriptorLength - 1)) 674 { 675 // 676 // invalid report descriptor length 677 // 678 return HIDP_STATUS_INVALID_REPORT_LENGTH; 679 } 680 681 for (Index = 0; Index < Report->ItemCount; Index++) 682 { 683 // 684 // get report item 685 // 686 ReportItem = &Report->Items[Index]; 687 688 // 689 // check usage page 690 // 691 CurrentUsagePage = (ReportItem->UsageMinimum >> 16); 692 693 // 694 // does usage page match 695 // 696 if (UsagePage != CurrentUsagePage) 697 continue; 698 699 // 700 // does the usage match 701 // 702 if (Usage != (ReportItem->UsageMinimum & 0xFFFF)) 703 continue; 704 705 // 706 // check if the specified usage is activated 707 // 708 ASSERT(ReportItem->ByteOffset < ReportDescriptorLength); 709 710 // 711 // one extra shift for skipping the prepended report id 712 // 713 Data = 0; 714 CopyFunction(&Data, &ReportDescriptor[ReportItem->ByteOffset + 1], min(sizeof(ULONG), ReportDescriptorLength - (ReportItem->ByteOffset + 1))); 715 716 // 717 // shift data 718 // 719 Data >>= ReportItem->Shift; 720 721 // 722 // clear unwanted bits 723 // 724 Data &= ReportItem->Mask; 725 726 if (ReportItem->Minimum > ReportItem->Maximum) 727 { 728 // 729 // logical boundaries are signed values 730 // 731 732 // FIXME: scale with physical min/max 733 if ((Data & ~(ReportItem->Mask >> 1)) != 0) 734 { 735 Data |= ~ReportItem->Mask; 736 } 737 } 738 else 739 { 740 // logical boundaries are absolute values 741 return HIDP_STATUS_BAD_LOG_PHY_VALUES; 742 } 743 744 // 745 // store result 746 // 747 *UsageValue = Data; 748 return HIDP_STATUS_SUCCESS; 749 } 750 751 // 752 // usage not found 753 // 754 return HIDP_STATUS_USAGE_NOT_FOUND; 755 } 756 757 ULONG 758 HidParser_GetScanCodeFromKbdUsage( 759 IN USAGE Usage) 760 { 761 if (Usage < sizeof(KeyboardScanCodes) / sizeof(KeyboardScanCodes[0])) 762 { 763 // 764 // valid usage 765 // 766 return KeyboardScanCodes[Usage]; 767 } 768 769 // 770 // invalid usage 771 // 772 return 0; 773 } 774 775 ULONG 776 HidParser_GetScanCodeFromCustUsage( 777 IN USAGE Usage) 778 { 779 ULONG i; 780 781 // 782 // find usage in array 783 // 784 for (i = 0; i < sizeof(CustomerScanCodes) / sizeof(CustomerScanCodes[0]); ++i) 785 { 786 if (CustomerScanCodes[i].Usage == Usage) 787 { 788 // 789 // valid usage 790 // 791 return CustomerScanCodes[i].ScanCode; 792 } 793 } 794 795 // 796 // invalid usage 797 // 798 return 0; 799 } 800 801 VOID 802 HidParser_DispatchKey( 803 IN PCHAR ScanCodes, 804 IN HIDP_KEYBOARD_DIRECTION KeyAction, 805 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, 806 IN PVOID InsertCodesContext) 807 { 808 ULONG Index; 809 ULONG Length = 0; 810 811 // 812 // count code length 813 // 814 for(Index = 0; Index < sizeof(ULONG); Index++) 815 { 816 if (ScanCodes[Index] == 0) 817 { 818 // 819 // last scan code 820 // 821 break; 822 } 823 824 // 825 // is this a key break 826 // 827 if (KeyAction == HidP_Keyboard_Break) 828 { 829 // 830 // add break - see USB HID to PS/2 Scan Code Translation Table 831 // 832 ScanCodes[Index] |= 0x80; 833 } 834 835 // 836 // more scan counts 837 // 838 Length++; 839 } 840 841 if (Length > 0) 842 { 843 // 844 // dispatch scan codes 845 // 846 InsertCodesProcedure(InsertCodesContext, ScanCodes, Length); 847 } 848 } 849 850 NTSTATUS 851 HidParser_TranslateKbdUsage( 852 IN USAGE Usage, 853 IN HIDP_KEYBOARD_DIRECTION KeyAction, 854 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, 855 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, 856 IN PVOID InsertCodesContext) 857 { 858 ULONG ScanCode; 859 CHAR FakeShift[] = {0xE0, 0x2A, 0x00}; 860 CHAR FakeCtrl[] = {0xE1, 0x1D, 0x00}; 861 862 // 863 // get scan code 864 // 865 ScanCode = HidParser_GetScanCodeFromKbdUsage(Usage); 866 if (!ScanCode) 867 { 868 // 869 // invalid lookup or no scan code available 870 // 871 DPRINT1("No Scan code for Usage %x\n", Usage); 872 return HIDP_STATUS_I8042_TRANS_UNKNOWN; 873 } 874 875 if (ScanCode & 0xFF00) 876 { 877 // 878 // swap scan code 879 // 880 ScanCode = NTOHS(ScanCode); 881 } 882 883 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Make) 884 { 885 // Print Screen generates additional FakeShift 886 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext); 887 } 888 889 if (Usage == 0x48) 890 { 891 // Pause/Break generates additional FakeCtrl. Note: it's always before key press/release. 892 HidParser_DispatchKey(FakeCtrl, KeyAction, InsertCodesProcedure, InsertCodesContext); 893 } 894 895 // 896 // FIXME: translate modifier states 897 // 898 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext); 899 900 if (Usage == 0x46 && KeyAction == HidP_Keyboard_Break) 901 { 902 // Print Screen generates additional FakeShift 903 HidParser_DispatchKey(FakeShift, KeyAction, InsertCodesProcedure, InsertCodesContext); 904 } 905 906 // 907 // done 908 // 909 return HIDP_STATUS_SUCCESS; 910 } 911 912 NTSTATUS 913 HidParser_TranslateCustUsage( 914 IN USAGE Usage, 915 IN HIDP_KEYBOARD_DIRECTION KeyAction, 916 IN OUT PHIDP_KEYBOARD_MODIFIER_STATE ModifierState, 917 IN PHIDP_INSERT_SCANCODES InsertCodesProcedure, 918 IN PVOID InsertCodesContext) 919 { 920 ULONG ScanCode; 921 922 // 923 // get scan code 924 // 925 ScanCode = HidParser_GetScanCodeFromCustUsage(Usage); 926 if (!ScanCode) 927 { 928 // 929 // invalid lookup or no scan code available 930 // 931 DPRINT1("No Scan code for Usage %x\n", Usage); 932 return HIDP_STATUS_I8042_TRANS_UNKNOWN; 933 } 934 935 if (ScanCode & 0xFF00) 936 { 937 // 938 // swap scan code 939 // 940 ScanCode = NTOHS(ScanCode); 941 } 942 943 // 944 // FIXME: translate modifier states 945 // 946 HidParser_DispatchKey((PCHAR)&ScanCode, KeyAction, InsertCodesProcedure, InsertCodesContext); 947 948 // 949 // done 950 // 951 return HIDP_STATUS_SUCCESS; 952 } 953