VOID ProcessKeyStroke()

in HidPkg/HidKeyboardDxe/HidKeyboard.c [905:1116]


VOID ProcessKeyStroke (
  IN UINT8                  *HidInputReportBuffer,
  IN UINTN                  HidInputReportBufferSize,
  IN HID_KB_DEV             *HidKeyboardDevice
)
{

  HID_KEY            HIDKey;
  UINT8              ModifierIndex;
  UINT8              Mask;
  UINT8              KeyCode;
  UINT8              LastKeyCode;
  UINT8              NewRepeatKey = 0;
  BOOLEAN            KeyPress;
  BOOLEAN            KeyRelease;
  EFI_KEY_DESCRIPTOR *KeyDescriptor;
  KEYBOARD_HID_INPUT_BUFFER *LastReport;
  UINTN              LastReportKeyCount;
  KEYBOARD_HID_INPUT_BUFFER *CurrentReport;
  UINTN              CurrentReportKeyCount;

  if ((HidKeyboardDevice == NULL) || (HidInputReportBuffer == NULL)) {
    DEBUG ((DEBUG_ERROR, "[%a] - Invalid input pointer.\n", __FUNCTION__));
    ASSERT((HidKeyboardDevice != NULL) && (HidInputReportBuffer != NULL));
    return;
  }

  if (HidInputReportBufferSize < INPUT_REPORT_HEADER_SIZE) {
    DEBUG ((DEBUG_ERROR, "[%a] - HID input report buffer is too small to process.\n", __FUNCTION__));
    return;
  }

  // if Last response doesn't exist, create it.
  if (HidKeyboardDevice->LastReport == NULL) {
    HidKeyboardDevice->LastReportSize = INPUT_REPORT_HEADER_SIZE;
    HidKeyboardDevice->LastReport = AllocateZeroPool(INPUT_REPORT_HEADER_SIZE);
    if (HidKeyboardDevice->LastReport == NULL) {
      DEBUG ((DEBUG_ERROR, "[%a] - Could not allocate empty last report.\n", __FUNCTION__));
      return;
    }

  }
  LastReport = HidKeyboardDevice->LastReport;
  LastReportKeyCount = HidKeyboardDevice->LastReportSize - INPUT_REPORT_HEADER_SIZE;
  CurrentReport = (KEYBOARD_HID_INPUT_BUFFER *)HidInputReportBuffer;
  CurrentReportKeyCount = HidInputReportBufferSize - INPUT_REPORT_HEADER_SIZE;

  //
  // Handle modifier key's pressing or releasing situation.
  // According to USB HID Firmware spec, Byte 0 uses following map of Modifier keys:
  // Bit0: Left Control,  Keycode: 0xe0
  // Bit1: Left Shift,    Keycode: 0xe1
  // Bit2: Left Alt,      Keycode: 0xe2
  // Bit3: Left GUI,      Keycode: 0xe3
  // Bit4: Right Control, Keycode: 0xe4
  // Bit5: Right Shift,   Keycode: 0xe5
  // Bit6: Right Alt,     Keycode: 0xe6
  // Bit7: Right GUI,     Keycode: 0xe7
  //
  for (ModifierIndex = 0; ModifierIndex < 8; ModifierIndex++) {
    Mask = (UINT8) (1 << ModifierIndex);
    if ((CurrentReport->ModifierKeys & Mask) != (LastReport->ModifierKeys & Mask)) {
      //
      // If current modifier key is up, then CurModifierMap & Mask = 0;
      // otherwise it is a non-zero value.
      // Insert the changed modifier key into key buffer.
      //
      HIDKey.KeyCode = (UINT8) (0xe0 + ModifierIndex);
      HIDKey.Down    = (BOOLEAN) ((CurrentReport->ModifierKeys & Mask) != 0);
      Enqueue (&HidKeyboardDevice->HidKeyQueue, &HIDKey, sizeof (HID_KEY));
    }
  }


  //
  // Handle normal key's releasing situation
  // Bytes 3 to n are for normal keycodes
  //
  KeyRelease = FALSE;
  for (LastKeyCode = 0; LastKeyCode < LastReportKeyCount; LastKeyCode++) {

    if (!HIDKBD_VALID_KEYCODE (LastReport->KeyCode[LastKeyCode])) {
      continue;
    }
    //
    // For any key in old keycode buffer, if it is not in current keycode buffer,
    // then it is released. Otherwise, it is not released.
    //
    KeyRelease = TRUE;
    for (KeyCode = 0; KeyCode < CurrentReportKeyCount; KeyCode++) {

      if (!HIDKBD_VALID_KEYCODE (CurrentReport->KeyCode[KeyCode])) {
        continue;
      }

      if (LastReport->KeyCode[LastKeyCode] == CurrentReport->KeyCode[KeyCode]) {
        KeyRelease = FALSE;
        break;
      }
    }

    if (KeyRelease) {
      HIDKey.KeyCode = LastReport->KeyCode[LastKeyCode];
      HIDKey.Down    = FALSE;
      //
      // The original repeat key is released.
      //
      if (LastReport->KeyCode[LastKeyCode] == HidKeyboardDevice->RepeatKey) {
        DEBUG ((DEBUG_VERBOSE, "HIDKeyboard: Resetting key repeat\n"));
        HidKeyboardDevice->RepeatKey = 0;
      }
    }
  }

  //
  // If original repeat key is released, cancel the repeat timer
  //
  if (HidKeyboardDevice->RepeatKey == 0) {
    DEBUG ((DEBUG_VERBOSE, "HIDKeyboard: Releasing Key Repeat Timer\n"));
    gBS->SetTimer (
           HidKeyboardDevice->RepeatTimer,
           TimerCancel,
           HIDKBD_REPEAT_RATE
           );
  }

  //
  // Handle normal key's pressing situation
  //
  KeyPress = FALSE;
  for (KeyCode = 0; KeyCode < CurrentReportKeyCount; KeyCode++) {

    if (!HIDKBD_VALID_KEYCODE (CurrentReport->KeyCode[KeyCode])) {
      continue;
    }
    //
    // For any key in current keycode buffer, if it is not in old keycode buffer,
    // then it is pressed. Otherwise, it is not pressed.
    //
    KeyPress = TRUE;
    for (LastKeyCode = 0; LastKeyCode < LastReportKeyCount; LastKeyCode++) {

      if (!HIDKBD_VALID_KEYCODE (LastReport->KeyCode[LastKeyCode])) {
        continue;
      }

      if (CurrentReport->KeyCode[KeyCode] == LastReport->KeyCode[LastKeyCode]) {
        KeyPress = FALSE;
        break;
      }
    }

    if (KeyPress) {
      HIDKey.KeyCode = CurrentReport->KeyCode[KeyCode];
      HIDKey.Down    = TRUE;
      DEBUG ((DEBUG_VERBOSE, "HIDKeyboard: Enqueuing Key = %d, on KeyPress\n", HIDKey.KeyCode));
      Enqueue (&HidKeyboardDevice->HidKeyQueue, &HIDKey, sizeof (HID_KEY));

      //
      // Handle repeat key
      //
      KeyDescriptor = GetKeyDescriptor (HidKeyboardDevice, CurrentReport->KeyCode[KeyCode]);
      if (KeyDescriptor == NULL) {
          return;
      }

      if (KeyDescriptor->Modifier == EFI_NUM_LOCK_MODIFIER || KeyDescriptor->Modifier == EFI_CAPS_LOCK_MODIFIER) {
        //
        // For NumLock or CapsLock pressed, there is no need to handle repeat key for them.
        //
        HidKeyboardDevice->RepeatKey = 0;
      } else {
        //
        // Prepare new repeat key, and clear the original one.
        //
        NewRepeatKey = CurrentReport->KeyCode[KeyCode];
        HidKeyboardDevice->RepeatKey = 0;
      }
    }
  }
  //
  // Copy the current report buffer as the last report buffer
  //
  FreePool(LastReport);
  HidKeyboardDevice->LastReport = AllocateCopyPool(HidInputReportBufferSize, HidInputReportBuffer);
  if (HidKeyboardDevice->LastReport == NULL) {
    DEBUG ((DEBUG_ERROR, "[%a] - could not allocate last report buffer\n", __FUNCTION__));
    HidKeyboardDevice->LastReportSize = 0;
  } else {
    HidKeyboardDevice->LastReportSize = HidInputReportBufferSize;
  }

  //
  // If there is new key pressed, update the RepeatKey value, and set the
  // timer to repeat the delay timer
  //
  if (NewRepeatKey != 0) {
    //
    // Sets trigger time to "Repeat Delay Time",
    // to trigger the repeat timer when the key is hold long
    // enough time.
    //
    gBS->SetTimer (
           HidKeyboardDevice->RepeatTimer,
           TimerRelative,
           HIDKBD_REPEAT_DELAY
           );
    DEBUG ((DEBUG_VERBOSE, "HIDKeyboard: Setting Key repeat timer\n"));
    DEBUG ((DEBUG_VERBOSE, "HIDKeyboard: New Repeat Key = %d, on KeyPress\n", NewRepeatKey));
    HidKeyboardDevice->RepeatKey = NewRepeatKey;
  }
}