inputhandler.c

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

C
1,569
字号
/*++

Copyright (c) 2004 - 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             

Module Name:

  InputHandler.C

Abstract:
  
  Implementation for handling user input from the User Interface

Revision History

--*/

#include "Ui.h"
#include "Setup.h"

EFI_STATUS
ReadString (
  IN  UI_MENU_OPTION              *MenuOption,
  OUT CHAR16                      *StringPtr
  )
{
  EFI_STATUS    Status;
  EFI_INPUT_KEY Key;
  CHAR16        NullCharacter;
  UINTN         ScreenSize;
  EFI_TAG       *Tag;
  CHAR16        Space[2];
  CHAR16        KeyPad[2];
  BOOLEAN       SelectionComplete;
  CHAR16        *TempString;
  CHAR16        *BufferedString;
  UINTN         Index;
  UINTN         Count;
  UINTN         Start;
  UINTN         Top;
  CHAR16        *PromptForDataString;
  UINTN         DimensionsWidth;
  UINTN         DimensionsHeight;
  BOOLEAN       CursorVisible;

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

  PromptForDataString = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);

  NullCharacter       = CHAR_NULL;
  ScreenSize          = GetStringWidth (PromptForDataString) / 2;
  Tag                 = MenuOption->ThisTag;
  Space[0]            = L' ';
  Space[1]            = CHAR_NULL;
  SelectionComplete   = FALSE;

  TempString          = EfiLibAllocateZeroPool (MenuOption->ThisTag->Maximum * 2);
  ASSERT (TempString);

  if (ScreenSize < (Tag->Maximum / (UINTN) 2)) {
    ScreenSize = Tag->Maximum / 2;
  }

  if ((ScreenSize + 2) > DimensionsWidth) {
    ScreenSize = DimensionsWidth - 2;
  }

  BufferedString = EfiLibAllocateZeroPool (ScreenSize * 2);
  ASSERT (BufferedString);

  Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;
  Top   = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;

  //
  // Display prompt for string
  //
  CreatePopUp (ScreenSize, 4, &NullCharacter, PromptForDataString, Space, &NullCharacter);

  gBS->FreePool (PromptForDataString);

  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));

  CursorVisible = gST->ConOut->Mode->CursorVisible;
  gST->ConOut->EnableCursor (gST->ConOut, TRUE);

  do {
    Status = WaitForKeyStroke (&Key);

    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
    switch (Key.UnicodeChar) {
    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_LEFT:
        break;

      case SCAN_RIGHT:
        break;

      case SCAN_ESC:
        gBS->FreePool (TempString);
        gBS->FreePool (BufferedString);
        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

    case CHAR_CARRIAGE_RETURN:
      if (GetStringWidth (StringPtr) >= MenuOption->ThisTag->Minimum) {
        SelectionComplete = TRUE;
        gBS->FreePool (TempString);
        gBS->FreePool (BufferedString);
        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
        return EFI_SUCCESS;
      } else {
        ScreenSize = GetStringWidth (gMiniString) / 2;
        CreatePopUp (ScreenSize, 4, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);
        //
        // Simply create a popup to tell the user that they had typed in too few characters.
        // To save code space, we can then treat this as an error and return back to the menu.
        //
        do {
          Status = WaitForKeyStroke (&Key);
        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
        gBS->FreePool (TempString);
        gBS->FreePool (BufferedString);
        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
        return EFI_DEVICE_ERROR;
      }

      break;

    case CHAR_BACKSPACE:
      if (StringPtr[0] != CHAR_NULL) {
        for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {
          TempString[Index] = StringPtr[Index];
        }
        //
        // Effectively truncate string by 1 character
        //
        TempString[Index - 1] = CHAR_NULL;
        EfiStrCpy (StringPtr, TempString);
      }

    default:
      //
      // If it is the beginning of the string, don't worry about checking maximum limits
      //
      if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
        StrnCpy (StringPtr, &Key.UnicodeChar, 1);
        StrnCpy (TempString, &Key.UnicodeChar, 1);
      } else if ((GetStringWidth (StringPtr) < MenuOption->ThisTag->Maximum) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
        KeyPad[0] = Key.UnicodeChar;
        KeyPad[1] = CHAR_NULL;
        EfiStrCat (StringPtr, KeyPad);
        EfiStrCat (TempString, KeyPad);
      }
      //
      // If the width of the input string is now larger than the screen, we nee to
      // adjust the index to start printing portions of the string
      //
      SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');

      PrintStringAt (Start + 1, Top + 3, BufferedString);

      if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
        Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
      } else {
        Index = 0;
      }

      for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
        BufferedString[Count] = StringPtr[Index];
      }

      PrintStringAt (Start + 1, Top + 3, BufferedString);
      break;
    }

    gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
    gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
  } while (!SelectionComplete);
  gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
  gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
  return Status;
}

EFI_STATUS
ReadPassword (
  IN  UI_MENU_OPTION              *MenuOption,
  IN  BOOLEAN                     PromptForPassword,
  IN  EFI_TAG                     *Tag,
  IN  EFI_IFR_DATA_ARRAY          *PageData,
  IN  BOOLEAN                     SecondEntry,
  IN  EFI_FILE_FORM_TAGS          *FileFormTags,
  OUT CHAR16                      *StringPtr
  )
{
  EFI_STATUS                  Status;
  UINTN                       PasswordSize;
  UINTN                       ScreenSize;
  CHAR16                      NullCharacter;
  CHAR16                      Space[2];
  EFI_INPUT_KEY               Key;
  CHAR16                      KeyPad[2];
  UINTN                       Index;
  UINTN                       Start;
  UINTN                       Top;
  CHAR16                      *TempString;
  CHAR16                      *TempString2;
  BOOLEAN                     Confirmation;
  BOOLEAN                     ConfirmationComplete;
  EFI_HII_CALLBACK_PACKET     *Packet;
  EFI_FORM_CALLBACK_PROTOCOL  *FormCallback;
  EFI_VARIABLE_DEFINITION     *VariableDefinition;
  UINTN                       DimensionsWidth;
  UINTN                       DimensionsHeight;

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

  VariableDefinition    = NULL;
  PasswordSize          = 0;
  NullCharacter         = CHAR_NULL;
  Space[0]              = L' ';
  Space[1]              = CHAR_NULL;
  Confirmation          = FALSE;
  ConfirmationComplete  = FALSE;
  Status                = EFI_SUCCESS;
  FormCallback          = NULL;
  Packet                = NULL;

  //
  // Remember that dynamic pages in an environment where all pages are not
  // dynamic require us to call back to the user to give them an opportunity
  // to register fresh information in the HII database so that we can extract it.
  //
  Status = gBS->HandleProtocol (
                  (VOID *) (UINTN) MenuOption->Tags[0].CallbackHandle,
                  &gEfiFormCallbackProtocolGuid,
                  &FormCallback
                  );

  TempString  = EfiLibAllocateZeroPool (MenuOption->ThisTag->Maximum * 2);
  TempString2 = EfiLibAllocateZeroPool (MenuOption->ThisTag->Maximum * 2);

  ASSERT (TempString);
  ASSERT (TempString2);

  if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
    //
    // Password requires a callback to determine if a password exists
    //
    PageData->Data->OpCode  = EFI_IFR_PASSWORD_OP;
    PageData->Data->Length  = 3;

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

    //
    // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)
    //
    PageData->Data->Data  = (VOID *) (UINTN) (UINT8) (0 + SecondEntry * 2);
    PageData->NvRamMap    = VariableDefinition->NvRamMap;

    if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
      Status = FormCallback->Callback (
                              FormCallback,
                              Tag->Key,
                              PageData,
                              &Packet
                              );
    }
    //
    // If error on return, continue with the reading of a typed in password to verify user knows password
    // If no error, there is no password set, so prompt for new password
    // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error
    //
    if (!EFI_ERROR (Status)) {
      PromptForPassword = FALSE;

      //
      // Simulate this as the second entry into this routine for an interactive behavior
      //
      SecondEntry = TRUE;
    } else if (Status == EFI_NOT_READY) {
Error:
      if (Packet != NULL) {
        //
        // Upon error, we will likely receive a string to print out
        // Display error popup
        //
        ScreenSize = EFI_MAX (GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2;
        CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);
        gBS->FreePool (Packet);

        do {
          Status = WaitForKeyStroke (&Key);
        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
      }

      gBS->FreePool (TempString);
      gBS->FreePool (TempString2);
      return EFI_NOT_READY;
    }
  }

  do {
    //
    // Display PopUp Screen
    //
    ScreenSize = GetStringWidth (gPromptForNewPassword) / 2;
    if (GetStringWidth (gConfirmPassword) / 2 > ScreenSize) {
      ScreenSize = GetStringWidth (gConfirmPassword) / 2;
    }

    Start = (DimensionsWidth - ScreenSize - 4) / 2 + gScreenDimensions.LeftColumn + 2;
    Top   = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;

    if (!Confirmation) {
      if (PromptForPassword) {
        CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForPassword, Space, &NullCharacter);
      } else {
        CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForNewPassword, Space, &NullCharacter);
      }
    } else {
      CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmPassword, Space, &NullCharacter);
      StringPtr[0] = CHAR_NULL;
    }

    do {
      Status = WaitForKeyStroke (&Key);

      switch (Key.UnicodeChar) {
      case CHAR_NULL:
        if (Key.ScanCode == SCAN_ESC) {
          return EFI_NOT_READY;
        }

        ConfirmationComplete = FALSE;
        break;

      case CHAR_CARRIAGE_RETURN:
        if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {
          //
          // User just typed a string in
          //
          PageData->Data->OpCode = EFI_IFR_PASSWORD_OP;

          //
          // If the user just typed in a password, Data = 1
          // If the user just typed in a password to confirm the previous password, Data = 2
          //
          if (!Confirmation) {
            PageData->Data->Length  = 3;
            PageData->Data->Data    = (VOID *) (UINTN) (UINT8) (1 + SecondEntry * 2);

            if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
              Status = FormCallback->Callback (
                                      FormCallback,
                                      Tag->Key,
                                      PageData,
                                      &Packet
                                      );
            }

            PageData->Data->Length  = sizeof (EFI_IFR_DATA_ENTRY);
            PageData->Data->Data    = (VOID *) TempString;
          } else {
            PageData->Data->Length  = 3;
            PageData->Data->Data    = (VOID *) (UINTN) (UINT8) (2 + SecondEntry * 2);

            if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {
              Status = FormCallback->Callback (
                                      FormCallback,
                                      Tag->Key,
                                      PageData,
                                      &Packet
                                      );
            }

⌨️ 快捷键说明

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