mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 12:54:17 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9554 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1161 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1161 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
Implementation for handling user input from the User Interfaces.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2009, 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.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Setup.h"
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get string or password input from user.
 | 
						|
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
  @param  Prompt            The prompt string shown on popup window.
 | 
						|
  @param  StringPtr         Destination for use input string.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If string input is read successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ReadString (
 | 
						|
  IN  UI_MENU_OPTION              *MenuOption,
 | 
						|
  IN  CHAR16                      *Prompt,
 | 
						|
  OUT CHAR16                      *StringPtr
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_INPUT_KEY           Key;
 | 
						|
  CHAR16                  NullCharacter;
 | 
						|
  UINTN                   ScreenSize;
 | 
						|
  CHAR16                  Space[2];
 | 
						|
  CHAR16                  KeyPad[2];
 | 
						|
  CHAR16                  *TempString;
 | 
						|
  CHAR16                  *BufferedString;
 | 
						|
  UINTN                   Index;
 | 
						|
  UINTN                   Count;
 | 
						|
  UINTN                   Start;
 | 
						|
  UINTN                   Top;
 | 
						|
  UINTN                   DimensionsWidth;
 | 
						|
  UINTN                   DimensionsHeight;
 | 
						|
  BOOLEAN                 CursorVisible;
 | 
						|
  UINTN                   Minimum;
 | 
						|
  UINTN                   Maximum;
 | 
						|
  FORM_BROWSER_STATEMENT  *Question;
 | 
						|
  BOOLEAN                 IsPassword;
 | 
						|
 | 
						|
  DimensionsWidth  = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
 | 
						|
  DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
 | 
						|
 | 
						|
  NullCharacter    = CHAR_NULL;
 | 
						|
  ScreenSize       = GetStringWidth (Prompt) / sizeof (CHAR16);
 | 
						|
  Space[0]         = L' ';
 | 
						|
  Space[1]         = CHAR_NULL;
 | 
						|
 | 
						|
  Question         = MenuOption->ThisTag;
 | 
						|
  Minimum          = (UINTN) Question->Minimum;
 | 
						|
  Maximum          = (UINTN) Question->Maximum;
 | 
						|
 | 
						|
  if (Question->Operand == EFI_IFR_PASSWORD_OP) {
 | 
						|
    IsPassword = TRUE;
 | 
						|
  } else {
 | 
						|
    IsPassword = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));
 | 
						|
  ASSERT (TempString);
 | 
						|
 | 
						|
  if (ScreenSize < (Maximum + 1)) {
 | 
						|
    ScreenSize = Maximum + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((ScreenSize + 2) > DimensionsWidth) {
 | 
						|
    ScreenSize = DimensionsWidth - 2;
 | 
						|
  }
 | 
						|
 | 
						|
  BufferedString = AllocateZeroPool (ScreenSize * 2);
 | 
						|
  ASSERT (BufferedString);
 | 
						|
 | 
						|
  Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;
 | 
						|
  Top   = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;
 | 
						|
 | 
						|
  //
 | 
						|
  // Display prompt for string
 | 
						|
  //
 | 
						|
  CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
 | 
						|
 | 
						|
  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);
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
    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:
 | 
						|
        FreePool (TempString);
 | 
						|
        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) >= ((Minimum + 1) * sizeof (CHAR16))) {
 | 
						|
 | 
						|
        FreePool (TempString);
 | 
						|
        FreePool (BufferedString);
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
 | 
						|
        gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // 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 {
 | 
						|
          CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);
 | 
						|
        } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
 | 
						|
 | 
						|
        FreePool (TempString);
 | 
						|
        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;
 | 
						|
        StrCpy (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) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
 | 
						|
        KeyPad[0] = Key.UnicodeChar;
 | 
						|
        KeyPad[1] = CHAR_NULL;
 | 
						|
        StrCat (StringPtr, KeyPad);
 | 
						|
        StrCat (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;
 | 
						|
      }
 | 
						|
 | 
						|
      if (IsPassword) {
 | 
						|
        gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
 | 
						|
      }
 | 
						|
 | 
						|
      for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
 | 
						|
        BufferedString[Count] = StringPtr[Index];
 | 
						|
 | 
						|
        if (IsPassword) {
 | 
						|
          PrintChar (L'*');
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (!IsPassword) {
 | 
						|
        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 (TRUE);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  This routine reads a numeric value from the user input.
 | 
						|
 | 
						|
  @param  Selection         Pointer to current selection.
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If numerical input is read successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetNumericInput (
 | 
						|
  IN  UI_MENU_SELECTION           *Selection,
 | 
						|
  IN  UI_MENU_OPTION              *MenuOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINTN                   Column;
 | 
						|
  UINTN                   Row;
 | 
						|
  CHAR16                  InputText[MAX_NUMERIC_INPUT_WIDTH];
 | 
						|
  CHAR16                  FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
 | 
						|
  UINT64                  PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
 | 
						|
  UINTN                   Count;
 | 
						|
  UINTN                   Loop;
 | 
						|
  BOOLEAN                 ManualInput;
 | 
						|
  BOOLEAN                 HexInput;
 | 
						|
  BOOLEAN                 DateOrTime;
 | 
						|
  UINTN                   InputWidth;
 | 
						|
  UINT64                  EditValue;
 | 
						|
  UINT64                  Step;
 | 
						|
  UINT64                  Minimum;
 | 
						|
  UINT64                  Maximum;
 | 
						|
  UINTN                   EraseLen;
 | 
						|
  UINT8                   Digital;
 | 
						|
  EFI_INPUT_KEY           Key;
 | 
						|
  EFI_HII_VALUE           *QuestionValue;
 | 
						|
  FORM_BROWSER_FORM       *Form;
 | 
						|
  FORM_BROWSER_FORMSET    *FormSet;
 | 
						|
  FORM_BROWSER_STATEMENT  *Question;
 | 
						|
 | 
						|
  Column            = MenuOption->OptCol;
 | 
						|
  Row               = MenuOption->Row;
 | 
						|
  PreviousNumber[0] = 0;
 | 
						|
  Count             = 0;
 | 
						|
  InputWidth        = 0;
 | 
						|
  Digital           = 0;
 | 
						|
 | 
						|
  FormSet       = Selection->FormSet;
 | 
						|
  Form          = Selection->Form;
 | 
						|
  Question      = MenuOption->ThisTag;
 | 
						|
  QuestionValue = &Question->HiiValue;
 | 
						|
  Step          = Question->Step;
 | 
						|
  Minimum       = Question->Minimum;
 | 
						|
  Maximum       = Question->Maximum;
 | 
						|
 | 
						|
  if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {
 | 
						|
    DateOrTime = TRUE;
 | 
						|
  } else {
 | 
						|
    DateOrTime = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Prepare Value to be edit
 | 
						|
  //
 | 
						|
  EraseLen = 0;
 | 
						|
  EditValue = 0;
 | 
						|
  if (Question->Operand == EFI_IFR_DATE_OP) {
 | 
						|
    Step = 1;
 | 
						|
    Minimum = 1;
 | 
						|
 | 
						|
    switch (MenuOption->Sequence) {
 | 
						|
    case 0:
 | 
						|
      Maximum = 12;
 | 
						|
      EraseLen = 4;
 | 
						|
      EditValue = QuestionValue->Value.date.Month;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 1:
 | 
						|
      Maximum = 31;
 | 
						|
      EraseLen = 3;
 | 
						|
      EditValue = QuestionValue->Value.date.Day;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 2:
 | 
						|
      Maximum = 0xffff;
 | 
						|
      EraseLen = 5;
 | 
						|
      EditValue = QuestionValue->Value.date.Year;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  } else if (Question->Operand == EFI_IFR_TIME_OP) {
 | 
						|
    Step = 1;
 | 
						|
    Minimum = 0;
 | 
						|
 | 
						|
    switch (MenuOption->Sequence) {
 | 
						|
    case 0:
 | 
						|
      Maximum = 23;
 | 
						|
      EraseLen = 4;
 | 
						|
      EditValue = QuestionValue->Value.time.Hour;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 1:
 | 
						|
      Maximum = 59;
 | 
						|
      EraseLen = 3;
 | 
						|
      EditValue = QuestionValue->Value.time.Minute;
 | 
						|
      break;
 | 
						|
 | 
						|
    case 2:
 | 
						|
      Maximum = 59;
 | 
						|
      EraseLen = 3;
 | 
						|
      EditValue = QuestionValue->Value.time.Second;
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Numeric
 | 
						|
    //
 | 
						|
    EraseLen = gOptionBlockWidth;
 | 
						|
    EditValue = QuestionValue->Value.u64;
 | 
						|
    if (Maximum == 0) {
 | 
						|
      Maximum = (UINT64) -1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Step == 0) {
 | 
						|
    ManualInput = TRUE;
 | 
						|
  } else {
 | 
						|
    ManualInput = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Question->Operand == EFI_IFR_NUMERIC_OP) &&
 | 
						|
      ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
 | 
						|
    HexInput = TRUE;
 | 
						|
  } else {
 | 
						|
    HexInput = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (ManualInput) {
 | 
						|
    if (HexInput) {
 | 
						|
      InputWidth = Question->StorageWidth * 2;
 | 
						|
    } else {
 | 
						|
      switch (Question->StorageWidth) {
 | 
						|
      case 1:
 | 
						|
        InputWidth = 3;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 2:
 | 
						|
        InputWidth = 5;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 4:
 | 
						|
        InputWidth = 10;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 8:
 | 
						|
        InputWidth = 20;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        InputWidth = 0;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    InputText[0] = LEFT_NUMERIC_DELIMITER;
 | 
						|
    SetUnicodeMem (InputText + 1, InputWidth, L' ');
 | 
						|
    ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
 | 
						|
    InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
 | 
						|
    InputText[InputWidth + 2] = L'\0';
 | 
						|
 | 
						|
    PrintAt (Column, Row, InputText);
 | 
						|
    Column++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // First time we enter this handler, we need to check to see if
 | 
						|
  // we were passed an increment or decrement directive
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    Key.UnicodeChar = CHAR_NULL;
 | 
						|
    if (gDirection != 0) {
 | 
						|
      Key.ScanCode  = gDirection;
 | 
						|
      gDirection    = 0;
 | 
						|
      goto TheKey2;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = WaitForKeyStroke (&Key);
 | 
						|
 | 
						|
TheKey2:
 | 
						|
    switch (Key.UnicodeChar) {
 | 
						|
 | 
						|
    case '+':
 | 
						|
    case '-':
 | 
						|
      if (Key.UnicodeChar == '+') {
 | 
						|
        Key.ScanCode = SCAN_RIGHT;
 | 
						|
      } else {
 | 
						|
        Key.ScanCode = SCAN_LEFT;
 | 
						|
      }
 | 
						|
      Key.UnicodeChar = CHAR_NULL;
 | 
						|
      goto TheKey2;
 | 
						|
 | 
						|
    case CHAR_NULL:
 | 
						|
      switch (Key.ScanCode) {
 | 
						|
      case SCAN_LEFT:
 | 
						|
      case SCAN_RIGHT:
 | 
						|
        if (DateOrTime) {
 | 
						|
          //
 | 
						|
          // By setting this value, we will return back to the caller.
 | 
						|
          // We need to do this since an auto-refresh will destroy the adjustment
 | 
						|
          // based on what the real-time-clock is showing.  So we always commit
 | 
						|
          // upon changing the value.
 | 
						|
          //
 | 
						|
          gDirection = SCAN_DOWN;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!ManualInput) {
 | 
						|
          if (Key.ScanCode == SCAN_LEFT) {
 | 
						|
            if (EditValue > Step) {
 | 
						|
              EditValue = EditValue - Step;
 | 
						|
            } else {
 | 
						|
              EditValue = Minimum;
 | 
						|
            }
 | 
						|
          } else if (Key.ScanCode == SCAN_RIGHT) {
 | 
						|
            EditValue = EditValue + Step;
 | 
						|
            if (EditValue > Maximum) {
 | 
						|
              EditValue = Maximum;
 | 
						|
            }
 | 
						|
          }
 | 
						|
 | 
						|
          ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
 | 
						|
          if (Question->Operand == EFI_IFR_DATE_OP) {
 | 
						|
            if (MenuOption->Sequence == 2) {
 | 
						|
              //
 | 
						|
              // Year
 | 
						|
              //
 | 
						|
              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
 | 
						|
            } else {
 | 
						|
              //
 | 
						|
              // Month/Day
 | 
						|
              //
 | 
						|
              UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
 | 
						|
            }
 | 
						|
 | 
						|
            if (MenuOption->Sequence == 0) {
 | 
						|
              FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
 | 
						|
            } else if (MenuOption->Sequence == 1) {
 | 
						|
              FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
 | 
						|
            }
 | 
						|
          } else if (Question->Operand == EFI_IFR_TIME_OP) {
 | 
						|
            UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
 | 
						|
 | 
						|
            if (MenuOption->Sequence == 0) {
 | 
						|
              FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
 | 
						|
            } else if (MenuOption->Sequence == 1) {
 | 
						|
              FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            QuestionValue->Value.u64 = EditValue;
 | 
						|
            PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
 | 
						|
          }
 | 
						|
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);
 | 
						|
          for (Loop = 0; Loop < EraseLen; Loop++) {
 | 
						|
            PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
 | 
						|
          }
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);
 | 
						|
 | 
						|
          if (MenuOption->Sequence == 0) {
 | 
						|
            PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
 | 
						|
            Column = MenuOption->OptCol + 1;
 | 
						|
          }
 | 
						|
 | 
						|
          PrintStringAt (Column, Row, FormattedNumber);
 | 
						|
 | 
						|
          if (!DateOrTime || MenuOption->Sequence == 2) {
 | 
						|
            PrintChar (RIGHT_NUMERIC_DELIMITER);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        goto EnterCarriageReturn;
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_UP:
 | 
						|
      case SCAN_DOWN:
 | 
						|
        goto EnterCarriageReturn;
 | 
						|
 | 
						|
      case SCAN_ESC:
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
EnterCarriageReturn:
 | 
						|
 | 
						|
    case CHAR_CARRIAGE_RETURN:
 | 
						|
      //
 | 
						|
      // Store Edit value back to Question
 | 
						|
      //
 | 
						|
      if (Question->Operand == EFI_IFR_DATE_OP) {
 | 
						|
        switch (MenuOption->Sequence) {
 | 
						|
        case 0:
 | 
						|
          QuestionValue->Value.date.Month = (UINT8) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        case 1:
 | 
						|
          QuestionValue->Value.date.Day = (UINT8) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        case 2:
 | 
						|
          QuestionValue->Value.date.Year = (UINT16) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      } else if (Question->Operand == EFI_IFR_TIME_OP) {
 | 
						|
        switch (MenuOption->Sequence) {
 | 
						|
        case 0:
 | 
						|
          QuestionValue->Value.time.Hour = (UINT8) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        case 1:
 | 
						|
          QuestionValue->Value.time.Minute = (UINT8) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        case 2:
 | 
						|
          QuestionValue->Value.time.Second = (UINT8) EditValue;
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Numeric
 | 
						|
        //
 | 
						|
        QuestionValue->Value.u64 = EditValue;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Check to see if the Value is something reasonable against consistency limitations.
 | 
						|
      // If not, let's kick the error specified.
 | 
						|
      //
 | 
						|
      Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Input value is not valid, restore Question Value
 | 
						|
        //
 | 
						|
        GetQuestionValue (FormSet, Form, Question, TRUE);
 | 
						|
      } else {
 | 
						|
        SetQuestionValue (FormSet, Form, Question, TRUE);
 | 
						|
        if (!DateOrTime || (Question->Storage != NULL)) {
 | 
						|
          //
 | 
						|
          // NV flag is unnecessary for RTC type of Date/Time
 | 
						|
          //
 | 
						|
          UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      return Status;
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHAR_BACKSPACE:
 | 
						|
      if (ManualInput) {
 | 
						|
        if (Count == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Remove a character
 | 
						|
        //
 | 
						|
        EditValue = PreviousNumber[Count - 1];
 | 
						|
        UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);
 | 
						|
        Count--;
 | 
						|
        Column--;
 | 
						|
        PrintAt (Column, Row, L" ");
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      if (ManualInput) {
 | 
						|
        if (HexInput) {
 | 
						|
          if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
 | 
						|
            Digital = (UINT8) (Key.UnicodeChar - L'0');
 | 
						|
          } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
 | 
						|
            Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);
 | 
						|
          } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
 | 
						|
            Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);
 | 
						|
          } else {
 | 
						|
            UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
 | 
						|
            UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        //
 | 
						|
        // If Count exceed input width, there is no way more is valid
 | 
						|
        //
 | 
						|
        if (Count >= InputWidth) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Someone typed something valid!
 | 
						|
        //
 | 
						|
        if (Count != 0) {
 | 
						|
          if (HexInput) {
 | 
						|
            EditValue = LShiftU64 (EditValue, 4) + Digital;
 | 
						|
          } else {
 | 
						|
            EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (HexInput) {
 | 
						|
            EditValue = Digital;
 | 
						|
          } else {
 | 
						|
            EditValue = Key.UnicodeChar - L'0';
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (EditValue > Maximum) {
 | 
						|
          UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, TRUE);
 | 
						|
          ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));
 | 
						|
          EditValue = PreviousNumber[Count];
 | 
						|
          break;
 | 
						|
        } else {
 | 
						|
          UpdateStatusBar (INPUT_ERROR, Question->QuestionFlags, FALSE);
 | 
						|
        }
 | 
						|
 | 
						|
        Count++;
 | 
						|
        ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));
 | 
						|
        PreviousNumber[Count] = EditValue;
 | 
						|
 | 
						|
        PrintCharAt (Column, Row, Key.UnicodeChar);
 | 
						|
        Column++;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  } while (TRUE);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get selection for OneOf and OrderedList (Left/Right will be ignored).
 | 
						|
 | 
						|
  @param  Selection         Pointer to current selection.
 | 
						|
  @param  MenuOption        Pointer to the current input menu.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS       If Option input is processed successfully
 | 
						|
  @retval EFI_DEVICE_ERROR  If operation fails
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetSelectionInputPopUp (
 | 
						|
  IN  UI_MENU_SELECTION           *Selection,
 | 
						|
  IN  UI_MENU_OPTION              *MenuOption
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_INPUT_KEY           Key;
 | 
						|
  UINTN                   Index;
 | 
						|
  CHAR16                  *StringPtr;
 | 
						|
  CHAR16                  *TempStringPtr;
 | 
						|
  UINTN                   Index2;
 | 
						|
  UINTN                   TopOptionIndex;
 | 
						|
  UINTN                   HighlightOptionIndex;
 | 
						|
  UINTN                   Start;
 | 
						|
  UINTN                   End;
 | 
						|
  UINTN                   Top;
 | 
						|
  UINTN                   Bottom;
 | 
						|
  UINTN                   PopUpMenuLines;
 | 
						|
  UINTN                   MenuLinesInView;
 | 
						|
  UINTN                   PopUpWidth;
 | 
						|
  CHAR16                  Character;
 | 
						|
  INT32                   SavedAttribute;
 | 
						|
  BOOLEAN                 ShowDownArrow;
 | 
						|
  BOOLEAN                 ShowUpArrow;
 | 
						|
  UINTN                   DimensionsWidth;
 | 
						|
  LIST_ENTRY              *Link;
 | 
						|
  BOOLEAN                 OrderedList;
 | 
						|
  UINT8                   *ValueArray;
 | 
						|
  UINT8                   ValueType;
 | 
						|
  EFI_HII_VALUE           HiiValue;
 | 
						|
  EFI_HII_VALUE           *HiiValueArray;
 | 
						|
  UINTN                   OptionCount;
 | 
						|
  QUESTION_OPTION         *OneOfOption;
 | 
						|
  QUESTION_OPTION         *CurrentOption;
 | 
						|
  FORM_BROWSER_STATEMENT  *Question;
 | 
						|
 | 
						|
  DimensionsWidth   = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
 | 
						|
 | 
						|
  ValueArray        = NULL;
 | 
						|
  ValueType         = 0;
 | 
						|
  CurrentOption     = NULL;
 | 
						|
  ShowDownArrow     = FALSE;
 | 
						|
  ShowUpArrow       = FALSE;
 | 
						|
 | 
						|
  StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
 | 
						|
  ASSERT (StringPtr);
 | 
						|
 | 
						|
  Question = MenuOption->ThisTag;
 | 
						|
  if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
 | 
						|
    ValueArray = Question->BufferValue;
 | 
						|
    ValueType = Question->ValueType;
 | 
						|
    OrderedList = TRUE;
 | 
						|
  } else {
 | 
						|
    OrderedList = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate Option count
 | 
						|
  //
 | 
						|
  if (OrderedList) {
 | 
						|
    for (Index = 0; Index < Question->MaxContainers; Index++) {
 | 
						|
      if (GetArrayData (ValueArray, ValueType, Index) == 0) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    OptionCount = Index;
 | 
						|
  } else {
 | 
						|
    OptionCount = 0;
 | 
						|
    Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
    while (!IsNull (&Question->OptionListHead, Link)) {
 | 
						|
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
 | 
						|
      OptionCount++;
 | 
						|
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Prepare HiiValue array
 | 
						|
  //
 | 
						|
  HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
 | 
						|
  ASSERT (HiiValueArray != NULL);
 | 
						|
  Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
  for (Index = 0; Index < OptionCount; Index++) {
 | 
						|
    if (OrderedList) {
 | 
						|
      HiiValueArray[Index].Type = ValueType;
 | 
						|
      HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
 | 
						|
    } else {
 | 
						|
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
      CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Move Suppressed Option to list tail
 | 
						|
  //
 | 
						|
  PopUpMenuLines = 0;
 | 
						|
  for (Index = 0; Index < OptionCount; Index++) {
 | 
						|
    OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
 | 
						|
    if (OneOfOption == NULL) {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    RemoveEntryList (&OneOfOption->Link);
 | 
						|
 | 
						|
    if ((OneOfOption->SuppressExpression != NULL) &&
 | 
						|
        (OneOfOption->SuppressExpression->Result.Value.b)) {
 | 
						|
      //
 | 
						|
      // This option is suppressed, insert to tail
 | 
						|
      //
 | 
						|
      InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Insert to head
 | 
						|
      //
 | 
						|
      InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
 | 
						|
 | 
						|
      PopUpMenuLines++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the number of one of options present and its size
 | 
						|
  //
 | 
						|
  PopUpWidth = 0;
 | 
						|
  HighlightOptionIndex = 0;
 | 
						|
  Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
  for (Index = 0; Index < PopUpMenuLines; Index++) {
 | 
						|
    OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
 | 
						|
    StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
 | 
						|
    if (StrLen (StringPtr) > PopUpWidth) {
 | 
						|
      PopUpWidth = StrLen (StringPtr);
 | 
						|
    }
 | 
						|
    FreePool (StringPtr);
 | 
						|
 | 
						|
    if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) {
 | 
						|
      //
 | 
						|
      // Find current selected Option for OneOf
 | 
						|
      //
 | 
						|
      HighlightOptionIndex = Index;
 | 
						|
    }
 | 
						|
 | 
						|
    Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Perform popup menu initialization.
 | 
						|
  //
 | 
						|
  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 - 1;
 | 
						|
 | 
						|
  MenuLinesInView = Bottom - Top - 1;
 | 
						|
  if (MenuLinesInView >= PopUpMenuLines) {
 | 
						|
    Top     = Top + (MenuLinesInView - PopUpMenuLines) / 2;
 | 
						|
    Bottom  = Top + PopUpMenuLines + 1;
 | 
						|
  } else {
 | 
						|
    ShowDownArrow = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (HighlightOptionIndex > (MenuLinesInView - 1)) {
 | 
						|
    TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
 | 
						|
  } else {
 | 
						|
    TopOptionIndex = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  do {
 | 
						|
    //
 | 
						|
    // 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 {
 | 
						|
        Character = BOXDRAW_HORIZONTAL;
 | 
						|
      }
 | 
						|
 | 
						|
      PrintChar (Character);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_DOWN_LEFT;
 | 
						|
    PrintChar (Character);
 | 
						|
    Character = BOXDRAW_VERTICAL;
 | 
						|
    for (Index = Top + 1; Index < Bottom; Index++) {
 | 
						|
      PrintCharAt (Start, Index, Character);
 | 
						|
      PrintCharAt (End - 1, Index, Character);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Move to top Option
 | 
						|
    //
 | 
						|
    Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
    for (Index = 0; Index < TopOptionIndex; Index++) {
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Display the One of options
 | 
						|
    //
 | 
						|
    Index2 = Top + 1;
 | 
						|
    for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
 | 
						|
      OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
      Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
 | 
						|
      StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
 | 
						|
      //
 | 
						|
      // If the string occupies multiple lines, truncate it to fit in one line,
 | 
						|
      // and append a "..." for indication.
 | 
						|
      //
 | 
						|
      if (StrLen (StringPtr) > (PopUpWidth - 1)) {
 | 
						|
        TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
 | 
						|
        ASSERT ( TempStringPtr != NULL );
 | 
						|
        CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
 | 
						|
        FreePool (StringPtr);
 | 
						|
        StringPtr = TempStringPtr;
 | 
						|
        StrCat (StringPtr, L"...");
 | 
						|
      }
 | 
						|
 | 
						|
      if (Index == HighlightOptionIndex) {
 | 
						|
          //
 | 
						|
          // Highlight the selected one
 | 
						|
          //
 | 
						|
          CurrentOption = OneOfOption;
 | 
						|
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
 | 
						|
          PrintStringAt (Start + 2, Index2, StringPtr);
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
 | 
						|
        } else {
 | 
						|
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
 | 
						|
          PrintStringAt (Start + 2, Index2, StringPtr);
 | 
						|
        }
 | 
						|
 | 
						|
      Index2++;
 | 
						|
      FreePool (StringPtr);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_UP_RIGHT;
 | 
						|
    PrintCharAt (Start, Bottom, Character);
 | 
						|
    for (Index = Start; Index + 2 < End; Index++) {
 | 
						|
      if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
 | 
						|
        Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
 | 
						|
      } else {
 | 
						|
        Character = BOXDRAW_HORIZONTAL;
 | 
						|
      }
 | 
						|
 | 
						|
      PrintChar (Character);
 | 
						|
    }
 | 
						|
 | 
						|
    Character = BOXDRAW_UP_LEFT;
 | 
						|
    PrintChar (Character);
 | 
						|
 | 
						|
    //
 | 
						|
    // Get User selection
 | 
						|
    //
 | 
						|
    Key.UnicodeChar = CHAR_NULL;
 | 
						|
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
 | 
						|
      Key.ScanCode  = gDirection;
 | 
						|
      gDirection    = 0;
 | 
						|
      goto TheKey;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = WaitForKeyStroke (&Key);
 | 
						|
 | 
						|
TheKey:
 | 
						|
    switch (Key.UnicodeChar) {
 | 
						|
    case '+':
 | 
						|
      if (OrderedList) {
 | 
						|
        if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
 | 
						|
          //
 | 
						|
          // Highlight reaches the top of the popup window, scroll one menu item.
 | 
						|
          //
 | 
						|
          TopOptionIndex--;
 | 
						|
          ShowDownArrow = TRUE;
 | 
						|
        }
 | 
						|
 | 
						|
        if (TopOptionIndex == 0) {
 | 
						|
          ShowUpArrow = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        if (HighlightOptionIndex > 0) {
 | 
						|
          HighlightOptionIndex--;
 | 
						|
 | 
						|
          ASSERT (CurrentOption != NULL);
 | 
						|
          SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case '-':
 | 
						|
      //
 | 
						|
      // If an ordered list op-code, we will allow for a popup of +/- keys
 | 
						|
      // to create an ordered list of items
 | 
						|
      //
 | 
						|
      if (OrderedList) {
 | 
						|
        if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
 | 
						|
            (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
 | 
						|
          //
 | 
						|
          // Highlight reaches the bottom of the popup window, scroll one menu item.
 | 
						|
          //
 | 
						|
          TopOptionIndex++;
 | 
						|
          ShowUpArrow = TRUE;
 | 
						|
        }
 | 
						|
 | 
						|
        if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
 | 
						|
          ShowDownArrow = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
 | 
						|
          HighlightOptionIndex++;
 | 
						|
 | 
						|
          ASSERT (CurrentOption != NULL);
 | 
						|
          SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHAR_NULL:
 | 
						|
      switch (Key.ScanCode) {
 | 
						|
      case SCAN_UP:
 | 
						|
      case SCAN_DOWN:
 | 
						|
        if (Key.ScanCode == SCAN_UP) {
 | 
						|
          if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
 | 
						|
            //
 | 
						|
            // Highlight reaches the top of the popup window, scroll one menu item.
 | 
						|
            //
 | 
						|
            TopOptionIndex--;
 | 
						|
            ShowDownArrow = TRUE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (TopOptionIndex == 0) {
 | 
						|
            ShowUpArrow = FALSE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (HighlightOptionIndex > 0) {
 | 
						|
            HighlightOptionIndex--;
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
 | 
						|
              (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
 | 
						|
            //
 | 
						|
            // Highlight reaches the bottom of the popup window, scroll one menu item.
 | 
						|
            //
 | 
						|
            TopOptionIndex++;
 | 
						|
            ShowUpArrow = TRUE;
 | 
						|
          }
 | 
						|
 | 
						|
          if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
 | 
						|
            ShowDownArrow = FALSE;
 | 
						|
          }
 | 
						|
 | 
						|
          if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
 | 
						|
            HighlightOptionIndex++;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case SCAN_ESC:
 | 
						|
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
 | 
						|
 | 
						|
        //
 | 
						|
        // Restore link list order for orderedlist
 | 
						|
        //
 | 
						|
        if (OrderedList) {
 | 
						|
          HiiValue.Type = ValueType;
 | 
						|
          HiiValue.Value.u64 = 0;
 | 
						|
          for (Index = 0; Index < Question->MaxContainers; Index++) {
 | 
						|
            HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
 | 
						|
            if (HiiValue.Value.u64 == 0) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
 | 
						|
            OneOfOption = ValueToOption (Question, &HiiValue);
 | 
						|
            if (OneOfOption == NULL) {
 | 
						|
              return EFI_NOT_FOUND;
 | 
						|
            }
 | 
						|
 | 
						|
            RemoveEntryList (&OneOfOption->Link);
 | 
						|
            InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        FreePool (HiiValueArray);
 | 
						|
        return EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
      default:
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHAR_CARRIAGE_RETURN:
 | 
						|
      //
 | 
						|
      // return the current selection
 | 
						|
      //
 | 
						|
      if (OrderedList) {
 | 
						|
        Index = 0;
 | 
						|
        Link = GetFirstNode (&Question->OptionListHead);
 | 
						|
        while (!IsNull (&Question->OptionListHead, Link)) {
 | 
						|
          OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
 | 
						|
 | 
						|
          SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);
 | 
						|
 | 
						|
          Index++;
 | 
						|
          if (Index > Question->MaxContainers) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
          Link = GetNextNode (&Question->OptionListHead, Link);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        ASSERT (CurrentOption != NULL);
 | 
						|
        CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
 | 
						|
      }
 | 
						|
 | 
						|
      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
 | 
						|
      FreePool (HiiValueArray);
 | 
						|
 | 
						|
      Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Input value is not valid, restore Question Value
 | 
						|
        //
 | 
						|
        GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
 | 
						|
      } else {
 | 
						|
        SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);
 | 
						|
        UpdateStatusBar (NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
 | 
						|
      }
 | 
						|
 | 
						|
      return Status;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  } while (TRUE);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Wait for a key to be pressed by user.
 | 
						|
 | 
						|
  @param Key         The key which is pressed by user.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS The function always completed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
WaitForKeyStroke (
 | 
						|
  OUT  EFI_INPUT_KEY           *Key
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  do {
 | 
						|
    UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0);
 | 
						|
    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
 | 
						|
  } while (EFI_ERROR(Status));
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |