inputhandler.c

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

C
1,569
字号
        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);
    }
    //
    // Display the One of options
    //
    Index2 = Top + 1;
    for (Index = MenuOption->TagIndex + TopOptionIndex;
         (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom);
         Index++
        ) {
      if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
        Token = MenuOption->Tags[Index].Text;
        if (Initialized) {
          for (ValueBackup = (UINT8) MenuOption->TagIndex;
               MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;
               ValueBackup++
              ) {
            if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {
              StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);
              break;
            }
          }
        } else {
          ValueBackup = (UINT8) Index;
          StringPtr   = GetToken (Token, MenuOption->Handle);
        }
        //
        // If the string occupies multiple lines, truncate it to fit in one line,
        // and append a "..." for indication.
        //
        if (EfiStrLen (StringPtr) > (PopUpWidth - 1)) {
          TempStringPtr = EfiLibAllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
          ASSERT ( TempStringPtr != NULL );
          EfiCopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
          gBS->FreePool (StringPtr);
          StringPtr = TempStringPtr;
          EfiStrCat (StringPtr, L"...");
        }
        //
        // Code to display the text should go here. Follwed by the [*]
        //
        if (MenuOption->Tags[ValueBackup].Suppress == TRUE) {
          //
          // Don't show the one, so decrease the Index2 for balance
          //
          Index2--;
        } else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) {
          //
          // Gray Out the one
          //
          gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND);
          PrintStringAt (Start + 2, Index2, StringPtr);
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
        } else if (MenuOption->Tags[ValueBackup].Value == TempValue) {
          //
          // Highlight the selected one
          //
          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);
          HighlightPosition = Index2;
        } else {
          gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
          PrintStringAt (Start + 2, Index2, StringPtr);
        }

        gBS->FreePool (StringPtr);
        Index2 = Index2 + 1;
      }
    }

    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 and change TempValue if necessary
    //
    //
    // Stop: One of pop-up menu
    //
    Key.UnicodeChar = CHAR_NULL;
    if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
      Key.ScanCode  = gDirection;
      gDirection    = 0;
      goto TheKey;
    }

    if (!KeyInitialized) {
      if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) {
        *KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key;
      } else {
        *KeyValue = MenuOption->ThisTag->Key;
      }

      KeyInitialized = TRUE;
    }

    Status = WaitForKeyStroke (&Key);

TheKey:
    switch (Key.UnicodeChar) {
    case '+':
    case '-':
      //
      // If an ordered list op-code, we will allow for a popup of +/- keys
      // to create an ordered list of items
      //
      if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
        if (Key.UnicodeChar == '+') {
          if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {
            //
            // Highlight reaches the top of the popup window, scroll one menu item.
            //
            TopOptionIndex--;
            ShowDownArrow = TRUE;
          }

          if (TopOptionIndex == 1) {
            ShowUpArrow = FALSE;
          }
        } else {
          if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {
            //
            // Highlight reaches the bottom of the popup window, scroll one menu item.
            //
            TopOptionIndex++;
            ShowUpArrow = TRUE;
          }

          if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {
            ShowDownArrow = FALSE;
          }
        }

        for (Index = MenuOption->TagIndex + TopOptionIndex;
             MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;
             Index++
            ) {
          if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) {
            continue;
          }

          if (Key.UnicodeChar == '+') {
            TempIndex = Index - 1;
          } else {
            TempIndex = Index + 1;
          }
          //
          // Is this the current tag we are on?
          //
          if (MenuOption->Tags[Index].Value == TempValue) {
            //
            // Is this prior tag a valid choice?  If not, bail out
            //
            if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
              //
              // Copy the destination tag to the local variable
              //
              EfiCopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG));
              //
              // Copy the current tag to the tag location before us
              //
              EfiCopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG));
              //
              // Copy the backed up tag to the current location
              //
              EfiCopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG));

              //
              // Adjust the array of values
              //
              for (Index = 0; Index < ValueCount; Index++) {
                if (ValueArrayBackup[Index] == (UINT8) TempValue) {
                  if (Key.UnicodeChar == '+') {
                    if (Index == 0) {
                      //
                      // It is the top of the array already
                      //
                      break;
                    }

                    TempIndex = Index - 1;
                  } else {
                    if ((Index + 1) == ValueCount) {
                      //
                      // It is the bottom of the array already
                      //
                      break;
                    }

                    TempIndex = Index + 1;
                  }

                  ValueBackup                 = ValueArrayBackup[TempIndex];
                  ValueArrayBackup[TempIndex] = ValueArrayBackup[Index];
                  ValueArrayBackup[Index]     = ValueBackup;
                  Initialized                 = TRUE;
                  break;
                }
              }
              break;
            } else {
              break;
            }
          }
        }
      }
      break;

    case CHAR_NULL:
      switch (Key.ScanCode) {
      case SCAN_UP:
      case SCAN_DOWN:
        if (Key.ScanCode == SCAN_UP) {
          if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {
            //
            // Highlight reaches the top of the popup window, scroll one menu item.
            //
            TopOptionIndex--;
            ShowDownArrow = TRUE;
          }

          if (TopOptionIndex == 1) {
            ShowUpArrow = FALSE;
          }
        } else {
          if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {
            //
            // Highlight reaches the bottom of the popup window, scroll one menu item.
            //
            TopOptionIndex++;
            ShowUpArrow = TRUE;
          }

          if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {
            ShowDownArrow = FALSE;
          }
        }

        for (Index = MenuOption->TagIndex + TopOptionIndex;
             MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;
             Index++
            ) {
          if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
            if (Initialized) {
              for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++)
                ;

              //
              // Did we hit the end of the array?  Either get the first TempValue or the next one
              //
              if (Key.ScanCode == SCAN_UP) {
                if (Index == 0) {
                  TempValue = ValueArrayBackup[0];
                } else {
                  TempValue = ValueArrayBackup[Index - 1];
                }
              } else {
                if ((Index + 1) == ValueCount) {
                  TempValue = ValueArrayBackup[Index];
                } else {
                  TempValue = ValueArrayBackup[Index + 1];
                }
              }
              break;
            } else {
              if (Key.ScanCode == SCAN_UP) {
                TempIndex = Index - 1;
                
                //
                // Keep going until meets meaningful tag.
                //
                while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP  &&
                         MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP        &&
                         MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)
                       ||
                       (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP  &&
                         (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {
                  TempIndex--;
                }
              } else {
                TempIndex = Index + 1;

                //
                // Keep going until meets meaningful tag.
                //
                while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP  &&
                         MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP        &&
                         MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)
                       ||
                       (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP  &&
                         (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {
                  TempIndex++;
                }
              }
              //
              // The option value is the same as what is stored in NV store.  This is where we take action
              //
              if (MenuOption->Tags[Index].Value == TempValue) {
                //
                // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option
                //
                if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {
                  TempValue = MenuOption->Tags[TempIndex].Value;
                  *KeyValue = MenuOption->Tags[TempIndex].Key;
                } else {
                  TempValue = MenuOption->Tags[Index].Value;
                  *KeyValue = MenuOption->Tags[Index].Key;
                }
                break;
              }
            }
          }
        }
        break;

      case SCAN_ESC:
        gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
        if (ValueArrayBackup != NULL) {
          gBS->FreePool (ValueArrayBackup);
        }

        return EFI_DEVICE_ERROR;

      default:
        break;
      }

      break;

    case CHAR_CARRIAGE_RETURN:
      //
      // return the current selection
      //
      if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {
        EfiCopyMem (ValueArray, ValueArrayBackup, ValueCount);
        gBS->FreePool (ValueArrayBackup);
      } else {
        *Value = TempValue;
      }

      gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
      return EFI_SUCCESS;

    default:
      break;
    }
  } while (1);

  gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
  return EFI_SUCCESS;
}

EFI_STATUS
WaitForKeyStroke (
  OUT  EFI_INPUT_KEY           *Key
  )
{
  EFI_STATUS  Status;

  do {
    UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);
    Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
  } while (EFI_ERROR(Status));

  return Status;
}

⌨️ 快捷键说明

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