inputhandler.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 1,569 行 · 第 1/4 页

C
1,569
字号
            FormattedNumber[2]  = RIGHT_NUMERIC_DELIMITER;
            FormattedNumber[1]  = FormattedNumber[0];
            FormattedNumber[0]  = L'0';
            Number              = 8;
          }

          PrintStringAt (Column, Row, FormattedNumber);
          if (Number == 10 && (NumericType == DATE_NUMERIC)) {
            PrintChar (RIGHT_NUMERIC_DELIMITER);
          }

          if (NumericType == REGULAR_NUMERIC) {
            PrintChar (RIGHT_NUMERIC_DELIMITER);
          }
        }
        break;

      case SCAN_UP:
      case SCAN_DOWN:
        goto EnterCarriageReturn;

      case SCAN_ESC:
        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

EnterCarriageReturn:

    case CHAR_CARRIAGE_RETURN:
      //
      // Check to see if the Value is something reasonable against consistency limitations.
      // If not, let's kick the error specified.
      //
      //
      // This gives us visibility to the FileFormTags->NvRamMap to check things
      // ActiveIfr is a global maintained by the menuing code to ensure that we
      // are pointing to the correct formset's file data.
      //
      for (Count = 0; Count < gActiveIfr; Count++) {
        FileFormTags = FileFormTags->NextFile;
      }

      ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);

      EfiCopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);

      //
      // Data associated with a NULL device (in the fake NV storage)
      //
      if (Tag->StorageWidth == (UINT16) 0) {
        EfiCopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);
      }
      //
      // If a late check is required save off the information.  This is used when consistency checks
      // are required, but certain values might be bound by an impossible consistency check such as
      // if two questions are bound by consistency checks and each only has two possible choices, there
      // would be no way for a user to switch the values.  Thus we require late checking.
      //
      if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {
        EfiCopyMem (&Tag->OldValue, &BackupValue, Tag->StorageWidth);
      } else {
        //
        // In theory, passing the value and the Id are sufficient to determine what needs
        // to be done.  The Id is the key to look for the entry needed in the Inconsistency
        // database.  That will yields operand and ID data - and since the ID's correspond
        // to the NV storage, we can determine the values for other IDs there.
        //
        if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {
          if (PopUp == 0x0000) {
            SelectionComplete = TRUE;
            break;
          }

          StringPtr = GetToken (PopUp, MenuOption->Handle);

          CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);

          do {
            Status = WaitForKeyStroke (&Key);

            switch (Key.UnicodeChar) {

            case CHAR_CARRIAGE_RETURN:
              SelectionComplete = TRUE;
              gBS->FreePool (StringPtr);
              break;

            default:
              break;
            }
          } while (!SelectionComplete);

          Tag->Value  = BackupValue;
          *Value      = BackupValue;

          EfiCopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);

          //
          // Data associated with a NULL device (in the fake NV storage)
          //
          if (Tag->StorageWidth == (UINT16) 0) {
            EfiCopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);
          }

          return EFI_DEVICE_ERROR;
        }
      }

      return EFI_SUCCESS;
      break;

    case CHAR_BACKSPACE:
      if (ManualInput) {
        if (Count == 0) {
          break;
        }
        //
        // Remove a character
        //
        Number  = PreviousNumber[Count - 1];
        *Value  = (UINT16) Number;
        UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);
        Count--;
        Column--;
        PrintAt (Column, Row, L" ");
      }
      break;

    default:
      if (ManualInput) {
        if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
          UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);
          break;
        }
        //
        // If Count 0-4 is complete, there is no way more is valid
        //
        if (Count > 4) {
          break;
        }
        //
        // Someone typed something valid!
        //
        if (Count != 0) {
          Number = Number * 10 + (Key.UnicodeChar - L'0');
        } else {
          Number = Key.UnicodeChar - L'0';
        }

        if (Number > Tag->Maximum) {
          UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);
          Number = PreviousNumber[Count];
          break;
        } else {
          UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);
        }

        Count++;

        PreviousNumber[Count] = Number;
        *Value                = (UINT16) Number;
        Tag->Value            = (UINT16) Number;

        PrintCharAt (Column, Row, Key.UnicodeChar);
        Column++;
      }
      break;
    }
  } while (!SelectionComplete);
  return EFI_SUCCESS;
}
//
// Notice that this is at least needed for the ordered list manipulation.
// Left/Right doesn't make sense for this op-code
//
EFI_STATUS
GetSelectionInputPopUp (
  IN  UI_MENU_OPTION              *MenuOption,
  IN  EFI_TAG                     *Tag,
  IN  UINTN                       ValueCount,
  OUT UINT16                      *Value,
  OUT UINT16                      *KeyValue
  )
{
  EFI_STATUS    Status;
  EFI_INPUT_KEY Key;
  UINTN         Index;
  UINTN         TempIndex;
  CHAR16        *StringPtr;
  CHAR16        *TempStringPtr;
  UINT16        Token;
  UINTN         Index2;
  UINTN         TopOptionIndex;
  UINTN         HighlightPosition;
  UINTN         Start;
  UINTN         End;
  UINTN         Top;
  UINTN         Bottom;
  UINT16        TempValue;
  UINTN         Count;
  UINTN         PopUpMenuLines;
  UINTN         MenuLinesInView;
  UINTN         PopUpWidth;
  CHAR16        Character;
  UINTN         FirstOption;
  BOOLEAN       FirstOptionFoundFlag;
  INT32         SavedAttribute;
  EFI_TAG       TagBackup;
  UINT8         *ValueArray;
  UINT8         *ValueArrayBackup;
  UINT8         ValueBackup;
  BOOLEAN       Initialized;
  BOOLEAN       KeyInitialized;
  BOOLEAN       ShowDownArrow;
  BOOLEAN       ShowUpArrow;
  UINTN         DimensionsWidth;
  UINTN         DimensionsHeight;

  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
  DimensionsHeight  = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;

  TempValue         = 0;
  TempIndex         = 0;
  ValueArray        = (UINT8 *) Value;
  ValueArrayBackup  = NULL;
  Initialized       = FALSE;
  KeyInitialized    = FALSE;
  ShowDownArrow     = FALSE;
  ShowUpArrow       = FALSE;

  if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
    ValueArrayBackup = EfiLibAllocateZeroPool (Tag->StorageWidth);
    ASSERT (ValueArrayBackup != NULL);
    EfiCopyMem (ValueArrayBackup, ValueArray, ValueCount);
    TempValue = *(UINT8 *) (ValueArray);
    if (ValueArray[0] != 0x00) {
      Initialized = TRUE;
    }

    for (Index = 0; ValueArray[Index] != 0x00; Index++)
      ;
    ValueCount = Index;
  } else {
    TempValue = *Value;
  }

  Count                 = 0;
  PopUpWidth            = 0;

  FirstOption           = MenuOption->TagIndex;
  FirstOptionFoundFlag  = FALSE;

  StringPtr             = EfiLibAllocateZeroPool ((gOptionBlockWidth + 1) * 2);
  ASSERT (StringPtr);

  //
  // Initialization for "One of" pop-up menu
  //
  //
  // Get the number of one of options present and its size
  //
  for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {
    if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP &&
        !MenuOption->Tags[Index].Suppress) {
      if (!FirstOptionFoundFlag) {
        FirstOption           = Index;
        FirstOptionFoundFlag  = TRUE;
      }

      Count++;
      Token = MenuOption->Tags[Index].Text;

      //
      // If this is an ordered list that is initialized
      //
      if (Initialized) {
        for (ValueBackup = (UINT8) MenuOption->TagIndex;
             MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP;
             ValueBackup++
            ) {
          if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {
            StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);
            break;
          }
        }
      } else {
        StringPtr = GetToken (Token, MenuOption->Handle);
      }

      if (EfiStrLen (StringPtr) > PopUpWidth) {
        PopUpWidth = EfiStrLen (StringPtr);
      }

      gBS->FreePool (StringPtr);
    }
  }
  //
  // Perform popup menu initialization.
  //
  PopUpMenuLines  = Count;
  PopUpWidth      = PopUpWidth + POPUP_PAD_SPACE_COUNT;

  SavedAttribute  = gST->ConOut->Mode->Attribute;
  gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);

  if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
    PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
  }

  Start           = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
  End             = Start + PopUpWidth + POPUP_FRAME_WIDTH;
  Top             = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
  Bottom          = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT;

  MenuLinesInView = Bottom - Top - 1;
  if (MenuLinesInView >= PopUpMenuLines) {
    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
    Bottom  = Top + PopUpMenuLines + 1;
  } else {
    TempValue     = MenuOption->Tags[MenuOption->TagIndex + 1].Value;
    ShowDownArrow = TRUE;
  }

  TopOptionIndex    = 1;
  HighlightPosition = 0;
  do {
    if (Initialized) {
      for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) {
        //
        // Set the value for the item we are looking for
        //
        Count = ValueArrayBackup[Index2];

        //
        // If we hit the end of the Array, we are complete
        //
        if (Count == 0) {
          break;
        }

        if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
          for (ValueBackup = (UINT8) MenuOption->TagIndex;
               MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;
               ValueBackup++
              ) {
            //
            // We just found what we are looking for
            //
            if (MenuOption->Tags[ValueBackup].Value == Count) {
              //
              // As long as the two indexes aren't the same, we have
              // two different op-codes we need to swap internally
              //
              if (Index != ValueBackup) {
                //
                // Backup destination tag, then copy source to destination, then copy backup to source location
                //
                EfiCopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG));
                EfiCopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG));
                EfiCopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG));
              } else {
                //
                // If the indexes are the same, then the op-code is where he belongs
                //
              }
            }
          }
        } else {
          //
          // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2
          //
          Index2--;
        }
      }
    }
    //
    // Clear that portion of the screen
    //
    ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);

    //
    // Draw "One of" pop-up menu
    //
    Character = BOXDRAW_DOWN_RIGHT;
    PrintCharAt (Start, Top, Character);
    for (Index = Start; Index + 2 < End; Index++) {
      if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
        Character = GEOMETRICSHAPE_UP_TRIANGLE;
      } else {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?