2 Implementation for handling user input from the User Interfaces.
4 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "FormDisplay.h"
18 Get maximum and minimum info from this opcode.
20 @param OpCode Pointer to the current input opcode.
21 @param Minimum The minimum size info for this opcode.
22 @param Maximum The maximum size info for this opcode.
27 IN EFI_IFR_OP_HEADER
*OpCode
,
32 EFI_IFR_STRING
*StringOp
;
33 EFI_IFR_PASSWORD
*PasswordOp
;
34 if (OpCode
->OpCode
== EFI_IFR_STRING_OP
) {
35 StringOp
= (EFI_IFR_STRING
*) OpCode
;
36 *Minimum
= StringOp
->MinSize
;
37 *Maximum
= StringOp
->MaxSize
;
38 } else if (OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
39 PasswordOp
= (EFI_IFR_PASSWORD
*) OpCode
;
40 *Minimum
= PasswordOp
->MinSize
;
41 *Maximum
= PasswordOp
->MaxSize
;
49 Get string or password input from user.
51 @param MenuOption Pointer to the current input menu.
52 @param Prompt The prompt string shown on popup window.
53 @param StringPtr Old user input and destination for use input string.
55 @retval EFI_SUCCESS If string input is read successfully
56 @retval EFI_DEVICE_ERROR If operation fails
61 IN UI_MENU_OPTION
*MenuOption
,
63 IN OUT CHAR16
*StringPtr
73 CHAR16
*BufferedString
;
79 UINTN DimensionsWidth
;
80 UINTN DimensionsHeight
;
82 BOOLEAN CursorVisible
;
85 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
88 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
89 DimensionsHeight
= gStatementDimensions
.BottomRow
- gStatementDimensions
.TopRow
;
91 NullCharacter
= CHAR_NULL
;
92 ScreenSize
= GetStringWidth (Prompt
) / sizeof (CHAR16
);
96 Question
= MenuOption
->ThisTag
;
97 GetFieldFromOp(Question
->OpCode
, &Minimum
, &Maximum
);
99 if (Question
->OpCode
->OpCode
== EFI_IFR_PASSWORD_OP
) {
105 TempString
= AllocateZeroPool ((Maximum
+ 1)* sizeof (CHAR16
));
108 if (ScreenSize
< (Maximum
+ 1)) {
109 ScreenSize
= Maximum
+ 1;
112 if ((ScreenSize
+ 2) > DimensionsWidth
) {
113 ScreenSize
= DimensionsWidth
- 2;
116 BufferedString
= AllocateZeroPool (ScreenSize
* 2);
117 ASSERT (BufferedString
);
119 Start
= (DimensionsWidth
- ScreenSize
- 2) / 2 + gStatementDimensions
.LeftColumn
+ 1;
120 Top
= ((DimensionsHeight
- 6) / 2) + gStatementDimensions
.TopRow
- 1;
123 // Display prompt for string
125 // CreateDialog (NULL, "", Prompt, Space, "", NULL);
126 CreateMultiStringPopUp (ScreenSize
, 4, &NullCharacter
, Prompt
, Space
, &NullCharacter
);
127 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
129 CursorVisible
= gST
->ConOut
->Mode
->CursorVisible
;
130 gST
->ConOut
->EnableCursor (gST
->ConOut
, TRUE
);
132 CurrentCursor
= GetStringWidth (StringPtr
) / 2 - 1;
133 if (CurrentCursor
!= 0) {
135 // Show the string which has beed saved before.
137 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
138 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
140 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
141 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
147 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
150 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
151 BufferedString
[Count
] = StringPtr
[Index
];
154 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
159 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
162 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
163 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ GetStringWidth (StringPtr
) / 2, Top
+ 3);
167 Status
= WaitForKeyStroke (&Key
);
168 ASSERT_EFI_ERROR (Status
);
170 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_BLACK
, EFI_LIGHTGRAY
));
171 switch (Key
.UnicodeChar
) {
173 switch (Key
.ScanCode
) {
175 if (CurrentCursor
> 0) {
181 if (CurrentCursor
< (GetStringWidth (StringPtr
) / 2 - 1)) {
187 FreePool (TempString
);
188 FreePool (BufferedString
);
189 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
190 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
191 return EFI_DEVICE_ERROR
;
199 case CHAR_CARRIAGE_RETURN
:
200 if (GetStringWidth (StringPtr
) >= ((Minimum
+ 1) * sizeof (CHAR16
))) {
202 FreePool (TempString
);
203 FreePool (BufferedString
);
204 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
205 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
209 // Simply create a popup to tell the user that they had typed in too few characters.
210 // To save code space, we can then treat this as an error and return back to the menu.
213 CreateDialog (&Key
, &NullCharacter
, gMiniString
, gPressEnter
, &NullCharacter
, NULL
);
214 } while (Key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
216 FreePool (TempString
);
217 FreePool (BufferedString
);
218 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
219 gST
->ConOut
->EnableCursor (gST
->ConOut
, CursorVisible
);
220 return EFI_DEVICE_ERROR
;
226 if (StringPtr
[0] != CHAR_NULL
&& CurrentCursor
!= 0) {
227 for (Index
= 0; Index
< CurrentCursor
- 1; Index
++) {
228 TempString
[Index
] = StringPtr
[Index
];
230 Count
= GetStringWidth (StringPtr
) / 2 - 1;
231 if (Count
>= CurrentCursor
) {
232 for (Index
= CurrentCursor
- 1, Index2
= CurrentCursor
; Index2
< Count
; Index
++, Index2
++) {
233 TempString
[Index
] = StringPtr
[Index2
];
235 TempString
[Index
] = CHAR_NULL
;
238 // Effectively truncate string by 1 character
240 StrCpy (StringPtr
, TempString
);
246 // If it is the beginning of the string, don't worry about checking maximum limits
248 if ((StringPtr
[0] == CHAR_NULL
) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
249 StrnCpy (StringPtr
, &Key
.UnicodeChar
, 1);
251 } else if ((GetStringWidth (StringPtr
) < ((Maximum
+ 1) * sizeof (CHAR16
))) && (Key
.UnicodeChar
!= CHAR_BACKSPACE
)) {
252 KeyPad
[0] = Key
.UnicodeChar
;
253 KeyPad
[1] = CHAR_NULL
;
254 Count
= GetStringWidth (StringPtr
) / 2 - 1;
255 if (CurrentCursor
< Count
) {
256 for (Index
= 0; Index
< CurrentCursor
; Index
++) {
257 TempString
[Index
] = StringPtr
[Index
];
259 TempString
[Index
] = CHAR_NULL
;
260 StrCat (TempString
, KeyPad
);
261 StrCat (TempString
, StringPtr
+ CurrentCursor
);
262 StrCpy (StringPtr
, TempString
);
264 StrCat (StringPtr
, KeyPad
);
270 // If the width of the input string is now larger than the screen, we nee to
271 // adjust the index to start printing portions of the string
273 SetUnicodeMem (BufferedString
, ScreenSize
- 1, L
' ');
274 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
276 if ((GetStringWidth (StringPtr
) / 2) > (DimensionsWidth
- 2)) {
277 Index
= (GetStringWidth (StringPtr
) / 2) - DimensionsWidth
+ 2;
283 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ 1, Top
+ 3);
286 for (Count
= 0; Index
+ 1 < GetStringWidth (StringPtr
) / 2; Index
++, Count
++) {
287 BufferedString
[Count
] = StringPtr
[Index
];
290 PrintCharAt ((UINTN
)-1, (UINTN
)-1, L
'*');
295 PrintStringAt (Start
+ 1, Top
+ 3, BufferedString
);
300 gST
->ConOut
->SetAttribute (gST
->ConOut
, EFI_TEXT_ATTR (EFI_LIGHTGRAY
, EFI_BLACK
));
301 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Start
+ CurrentCursor
+ 1, Top
+ 3);
307 Adjust the value to the correct one. Rules follow the sample:
308 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
309 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
311 @param QuestionValue Pointer to current question.
312 @param Sequence The sequence of the field in the question.
315 AdjustQuestionValue (
316 IN EFI_HII_VALUE
*QuestionValue
,
325 Month
= QuestionValue
->Value
.date
.Month
;
326 Year
= QuestionValue
->Value
.date
.Year
;
331 if ((Year
% 4) == 0 && ((Year
% 100) != 0 || (Year
% 400) == 0)) {
349 // Change the month area.
352 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
353 QuestionValue
->Value
.date
.Day
= Maximum
;
358 // Change the Year area.
361 if (QuestionValue
->Value
.date
.Day
> Maximum
) {
362 QuestionValue
->Value
.date
.Day
= Minimum
;
368 Get field info from numeric opcode.
370 @param OpCode Pointer to the current input opcode.
371 @param Minimum The minimum size info for this opcode.
372 @param Maximum The maximum size info for this opcode.
373 @param Step The step size info for this opcode.
374 @param StorageWidth The storage width info for this opcode.
379 IN EFI_IFR_OP_HEADER
*OpCode
,
383 OUT UINT16
*StorageWidth
386 EFI_IFR_NUMERIC
*NumericOp
;
388 NumericOp
= (EFI_IFR_NUMERIC
*) OpCode
;
390 switch (NumericOp
->Flags
& EFI_IFR_NUMERIC_SIZE
) {
391 case EFI_IFR_NUMERIC_SIZE_1
:
392 *Minimum
= NumericOp
->data
.u8
.MinValue
;
393 *Maximum
= NumericOp
->data
.u8
.MaxValue
;
394 *Step
= NumericOp
->data
.u8
.Step
;
395 *StorageWidth
= (UINT16
) sizeof (UINT8
);
398 case EFI_IFR_NUMERIC_SIZE_2
:
399 *Minimum
= NumericOp
->data
.u16
.MinValue
;
400 *Maximum
= NumericOp
->data
.u16
.MaxValue
;
401 *Step
= NumericOp
->data
.u16
.Step
;
402 *StorageWidth
= (UINT16
) sizeof (UINT16
);
405 case EFI_IFR_NUMERIC_SIZE_4
:
406 *Minimum
= NumericOp
->data
.u32
.MinValue
;
407 *Maximum
= NumericOp
->data
.u32
.MaxValue
;
408 *Step
= NumericOp
->data
.u32
.Step
;
409 *StorageWidth
= (UINT16
) sizeof (UINT32
);
412 case EFI_IFR_NUMERIC_SIZE_8
:
413 *Minimum
= NumericOp
->data
.u64
.MinValue
;
414 *Maximum
= NumericOp
->data
.u64
.MaxValue
;
415 *Step
= NumericOp
->data
.u64
.Step
;
416 *StorageWidth
= (UINT16
) sizeof (UINT64
);
424 *Maximum
= (UINT64
) -1;
429 This routine reads a numeric value from the user input.
431 @param MenuOption Pointer to the current input menu.
433 @retval EFI_SUCCESS If numerical input is read successfully
434 @retval EFI_DEVICE_ERROR If operation fails
439 IN UI_MENU_OPTION
*MenuOption
445 CHAR16 InputText
[MAX_NUMERIC_INPUT_WIDTH
];
446 CHAR16 FormattedNumber
[MAX_NUMERIC_INPUT_WIDTH
- 1];
447 UINT64 PreviousNumber
[MAX_NUMERIC_INPUT_WIDTH
- 3];
461 EFI_HII_VALUE
*QuestionValue
;
462 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
463 EFI_IFR_NUMERIC
*NumericOp
;
466 Column
= MenuOption
->OptCol
;
467 Row
= MenuOption
->Row
;
468 PreviousNumber
[0] = 0;
477 Question
= MenuOption
->ThisTag
;
478 QuestionValue
= &Question
->CurrentValue
;
481 // Only two case, user can enter to this function: Enter and +/- case.
482 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
484 ManualInput
= (BOOLEAN
)(gDirection
== 0 ? TRUE
: FALSE
);
486 if ((Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) || (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
)) {
493 // Prepare Value to be edit
497 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
501 switch (MenuOption
->Sequence
) {
505 EditValue
= QuestionValue
->Value
.date
.Month
;
509 switch (QuestionValue
->Value
.date
.Month
) {
511 if ((QuestionValue
->Value
.date
.Year
% 4) == 0 &&
512 ((QuestionValue
->Value
.date
.Year
% 100) != 0 ||
513 (QuestionValue
->Value
.date
.Year
% 400) == 0)) {
531 EditValue
= QuestionValue
->Value
.date
.Day
;
537 EditValue
= QuestionValue
->Value
.date
.Year
;
543 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
547 switch (MenuOption
->Sequence
) {
551 EditValue
= QuestionValue
->Value
.time
.Hour
;
557 EditValue
= QuestionValue
->Value
.time
.Minute
;
563 EditValue
= QuestionValue
->Value
.time
.Second
;
570 ASSERT (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
);
571 NumericOp
= (EFI_IFR_NUMERIC
*) Question
->OpCode
;
572 GetValueFromNum(Question
->OpCode
, &Minimum
, &Maximum
, &Step
, &StorageWidth
);
573 EditValue
= QuestionValue
->Value
.u64
;
574 EraseLen
= gOptionBlockWidth
;
577 if ((Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) && (NumericOp
!= NULL
) &&
578 ((NumericOp
->Flags
& EFI_IFR_DISPLAY
) == EFI_IFR_DISPLAY_UINT_HEX
)) {
585 // Enter from "Enter" input, clear the old word showing.
588 if (Question
->OpCode
->OpCode
== EFI_IFR_NUMERIC_OP
) {
590 InputWidth
= StorageWidth
* 2;
592 switch (StorageWidth
) {
615 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
616 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
617 ASSERT (InputWidth
+ 2 < MAX_NUMERIC_INPUT_WIDTH
);
618 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
619 InputText
[InputWidth
+ 2] = L
'\0';
621 PrintStringAt (Column
, Row
, InputText
);
625 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
626 if (MenuOption
->Sequence
== 2) {
632 if (MenuOption
->Sequence
== 0) {
633 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
634 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
636 SetUnicodeMem (InputText
, InputWidth
, L
' ');
639 if (MenuOption
->Sequence
== 2) {
640 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
642 InputText
[InputWidth
+ 1] = DATE_SEPARATOR
;
644 InputText
[InputWidth
+ 2] = L
'\0';
646 PrintStringAt (Column
, Row
, InputText
);
647 if (MenuOption
->Sequence
== 0) {
652 if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
655 if (MenuOption
->Sequence
== 0) {
656 InputText
[0] = LEFT_NUMERIC_DELIMITER
;
657 SetUnicodeMem (InputText
+ 1, InputWidth
, L
' ');
659 SetUnicodeMem (InputText
, InputWidth
, L
' ');
662 if (MenuOption
->Sequence
== 2) {
663 InputText
[InputWidth
+ 1] = RIGHT_NUMERIC_DELIMITER
;
665 InputText
[InputWidth
+ 1] = TIME_SEPARATOR
;
667 InputText
[InputWidth
+ 2] = L
'\0';
669 PrintStringAt (Column
, Row
, InputText
);
670 if (MenuOption
->Sequence
== 0) {
677 // First time we enter this handler, we need to check to see if
678 // we were passed an increment or decrement directive
681 Key
.UnicodeChar
= CHAR_NULL
;
682 if (gDirection
!= 0) {
683 Key
.ScanCode
= gDirection
;
688 Status
= WaitForKeyStroke (&Key
);
691 switch (Key
.UnicodeChar
) {
695 if (Key
.UnicodeChar
== '+') {
696 Key
.ScanCode
= SCAN_RIGHT
;
698 Key
.ScanCode
= SCAN_LEFT
;
700 Key
.UnicodeChar
= CHAR_NULL
;
704 switch (Key
.ScanCode
) {
707 if (DateOrTime
&& !ManualInput
) {
709 // By setting this value, we will return back to the caller.
710 // We need to do this since an auto-refresh will destroy the adjustment
711 // based on what the real-time-clock is showing. So we always commit
712 // upon changing the value.
714 gDirection
= SCAN_DOWN
;
717 if ((Step
!= 0) && !ManualInput
) {
718 if (Key
.ScanCode
== SCAN_LEFT
) {
719 if (EditValue
>= Minimum
+ Step
) {
720 EditValue
= EditValue
- Step
;
721 } else if (EditValue
> Minimum
){
726 } else if (Key
.ScanCode
== SCAN_RIGHT
) {
727 if (EditValue
+ Step
<= Maximum
) {
728 EditValue
= EditValue
+ Step
;
729 } else if (EditValue
< Maximum
) {
736 ZeroMem (FormattedNumber
, 21 * sizeof (CHAR16
));
737 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
738 if (MenuOption
->Sequence
== 2) {
742 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%04d", (UINT16
) EditValue
);
747 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
750 if (MenuOption
->Sequence
== 0) {
751 ASSERT (EraseLen
>= 2);
752 FormattedNumber
[EraseLen
- 2] = DATE_SEPARATOR
;
753 } else if (MenuOption
->Sequence
== 1) {
754 ASSERT (EraseLen
>= 1);
755 FormattedNumber
[EraseLen
- 1] = DATE_SEPARATOR
;
757 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
758 UnicodeSPrint (FormattedNumber
, 21 * sizeof (CHAR16
), L
"%02d", (UINT8
) EditValue
);
760 if (MenuOption
->Sequence
== 0) {
761 ASSERT (EraseLen
>= 2);
762 FormattedNumber
[EraseLen
- 2] = TIME_SEPARATOR
;
763 } else if (MenuOption
->Sequence
== 1) {
764 ASSERT (EraseLen
>= 1);
765 FormattedNumber
[EraseLen
- 1] = TIME_SEPARATOR
;
768 QuestionValue
->Value
.u64
= EditValue
;
769 PrintFormattedNumber (Question
, FormattedNumber
, 21 * sizeof (CHAR16
));
772 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetFieldTextColor ());
773 for (Loop
= 0; Loop
< EraseLen
; Loop
++) {
774 PrintStringAt (MenuOption
->OptCol
+ Loop
, MenuOption
->Row
, L
" ");
776 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
778 if (MenuOption
->Sequence
== 0) {
779 PrintCharAt (MenuOption
->OptCol
, Row
, LEFT_NUMERIC_DELIMITER
);
780 Column
= MenuOption
->OptCol
+ 1;
783 PrintStringAt (Column
, Row
, FormattedNumber
);
785 if (!DateOrTime
|| MenuOption
->Sequence
== 2) {
786 PrintCharAt ((UINTN
)-1, (UINTN
)-1, RIGHT_NUMERIC_DELIMITER
);
790 goto EnterCarriageReturn
;
795 goto EnterCarriageReturn
;
798 return EFI_DEVICE_ERROR
;
808 case CHAR_CARRIAGE_RETURN
:
810 // Validate input value with Minimum value.
812 if (EditValue
< Minimum
) {
813 UpdateStatusBar (INPUT_ERROR
, TRUE
);
816 UpdateStatusBar (INPUT_ERROR
, FALSE
);
819 CopyMem (&gUserInput
->InputValue
, &Question
->CurrentValue
, sizeof (EFI_HII_VALUE
));
820 QuestionValue
= &gUserInput
->InputValue
;
822 // Store Edit value back to Question
824 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
) {
825 switch (MenuOption
->Sequence
) {
827 QuestionValue
->Value
.date
.Month
= (UINT8
) EditValue
;
831 QuestionValue
->Value
.date
.Day
= (UINT8
) EditValue
;
835 QuestionValue
->Value
.date
.Year
= (UINT16
) EditValue
;
841 } else if (Question
->OpCode
->OpCode
== EFI_IFR_TIME_OP
) {
842 switch (MenuOption
->Sequence
) {
844 QuestionValue
->Value
.time
.Hour
= (UINT8
) EditValue
;
848 QuestionValue
->Value
.time
.Minute
= (UINT8
) EditValue
;
852 QuestionValue
->Value
.time
.Second
= (UINT8
) EditValue
;
862 QuestionValue
->Value
.u64
= EditValue
;
866 // Adjust the value to the correct one.
867 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
868 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
870 if (Question
->OpCode
->OpCode
== EFI_IFR_DATE_OP
&&
871 (MenuOption
->Sequence
== 0 || MenuOption
->Sequence
== 2)) {
872 AdjustQuestionValue (QuestionValue
, (UINT8
)MenuOption
->Sequence
);
884 // Remove a character
886 EditValue
= PreviousNumber
[Count
- 1];
887 UpdateStatusBar (INPUT_ERROR
, FALSE
);
890 PrintStringAt (Column
, Row
, L
" ");
897 if ((Key
.UnicodeChar
>= L
'0') && (Key
.UnicodeChar
<= L
'9')) {
898 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'0');
899 } else if ((Key
.UnicodeChar
>= L
'A') && (Key
.UnicodeChar
<= L
'F')) {
900 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'A' + 0x0A);
901 } else if ((Key
.UnicodeChar
>= L
'a') && (Key
.UnicodeChar
<= L
'f')) {
902 Digital
= (UINT8
) (Key
.UnicodeChar
- L
'a' + 0x0A);
904 UpdateStatusBar (INPUT_ERROR
, TRUE
);
908 if (Key
.UnicodeChar
> L
'9' || Key
.UnicodeChar
< L
'0') {
909 UpdateStatusBar (INPUT_ERROR
, TRUE
);
915 // If Count exceed input width, there is no way more is valid
917 if (Count
>= InputWidth
) {
921 // Someone typed something valid!
925 EditValue
= LShiftU64 (EditValue
, 4) + Digital
;
927 EditValue
= MultU64x32 (EditValue
, 10) + (Key
.UnicodeChar
- L
'0');
933 EditValue
= Key
.UnicodeChar
- L
'0';
937 if (EditValue
> Maximum
) {
938 UpdateStatusBar (INPUT_ERROR
, TRUE
);
939 ASSERT (Count
< sizeof (PreviousNumber
) / sizeof (PreviousNumber
[0]));
940 EditValue
= PreviousNumber
[Count
];
943 UpdateStatusBar (INPUT_ERROR
, FALSE
);
947 ASSERT (Count
< (sizeof (PreviousNumber
) / sizeof (PreviousNumber
[0])));
948 PreviousNumber
[Count
] = EditValue
;
950 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetHighlightTextColor ());
951 PrintCharAt (Column
, Row
, Key
.UnicodeChar
);
960 Adjust option order base on the question value.
962 @param Question Pointer to current question.
963 @param PopUpMenuLines The line number of the pop up menu.
965 @retval EFI_SUCCESS If Option input is processed successfully
966 @retval EFI_DEVICE_ERROR If operation fails
971 IN FORM_DISPLAY_ENGINE_STATEMENT
*Question
,
972 OUT UINTN
*PopUpMenuLines
976 EFI_IFR_ORDERED_LIST
*OrderList
;
980 DISPLAY_QUESTION_OPTION
*OneOfOption
;
981 EFI_HII_VALUE
*HiiValueArray
;
983 Link
= GetFirstNode (&Question
->OptionListHead
);
984 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
985 ValueArray
= Question
->CurrentValue
.Buffer
;
986 ValueType
= OneOfOption
->OptionOpCode
->Type
;
987 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
989 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
990 if (GetArrayData (ValueArray
, ValueType
, Index
) == 0) {
995 *PopUpMenuLines
= Index
;
998 // Prepare HiiValue array
1000 HiiValueArray
= AllocateZeroPool (*PopUpMenuLines
* sizeof (EFI_HII_VALUE
));
1001 ASSERT (HiiValueArray
!= NULL
);
1003 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1004 HiiValueArray
[Index
].Type
= ValueType
;
1005 HiiValueArray
[Index
].Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1008 for (Index
= 0; Index
< *PopUpMenuLines
; Index
++) {
1009 OneOfOption
= ValueToOption (Question
, &HiiValueArray
[*PopUpMenuLines
- Index
- 1]);
1010 if (OneOfOption
== NULL
) {
1011 return EFI_NOT_FOUND
;
1014 RemoveEntryList (&OneOfOption
->Link
);
1019 InsertHeadList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1022 FreePool (HiiValueArray
);
1028 Base on the type to compare the value.
1030 @param Value1 The first value need to compare.
1031 @param Value2 The second value need to compare.
1032 @param Type The value type for above two values.
1034 @retval TRUE The two value are same.
1035 @retval FALSE The two value are different.
1040 IN EFI_IFR_TYPE_VALUE
*Value1
,
1041 IN EFI_IFR_TYPE_VALUE
*Value2
,
1046 case EFI_IFR_TYPE_BOOLEAN
:
1047 case EFI_IFR_TYPE_NUM_SIZE_8
:
1048 return (BOOLEAN
) (Value1
->u8
== Value2
->u8
);
1050 case EFI_IFR_TYPE_NUM_SIZE_16
:
1051 return (BOOLEAN
) (Value1
->u16
== Value2
->u16
);
1053 case EFI_IFR_TYPE_NUM_SIZE_32
:
1054 return (BOOLEAN
) (Value1
->u32
== Value2
->u32
);
1056 case EFI_IFR_TYPE_NUM_SIZE_64
:
1057 return (BOOLEAN
) (Value1
->u64
== Value2
->u64
);
1066 Base on the type to set the value.
1068 @param Dest The dest value.
1069 @param Source The source value.
1070 @param Type The value type for above two values.
1075 OUT EFI_IFR_TYPE_VALUE
*Dest
,
1076 IN EFI_IFR_TYPE_VALUE
*Source
,
1081 case EFI_IFR_TYPE_BOOLEAN
:
1082 Dest
->b
= Source
->b
;
1085 case EFI_IFR_TYPE_NUM_SIZE_8
:
1086 Dest
->u8
= Source
->u8
;
1089 case EFI_IFR_TYPE_NUM_SIZE_16
:
1090 Dest
->u16
= Source
->u16
;
1093 case EFI_IFR_TYPE_NUM_SIZE_32
:
1094 Dest
->u32
= Source
->u32
;
1097 case EFI_IFR_TYPE_NUM_SIZE_64
:
1098 Dest
->u64
= Source
->u64
;
1108 Get selection for OneOf and OrderedList (Left/Right will be ignored).
1110 @param MenuOption Pointer to the current input menu.
1112 @retval EFI_SUCCESS If Option input is processed successfully
1113 @retval EFI_DEVICE_ERROR If operation fails
1117 GetSelectionInputPopUp (
1118 IN UI_MENU_OPTION
*MenuOption
1125 CHAR16
*TempStringPtr
;
1127 UINTN TopOptionIndex
;
1128 UINTN HighlightOptionIndex
;
1133 UINTN PopUpMenuLines
;
1134 UINTN MenuLinesInView
;
1137 INT32 SavedAttribute
;
1138 BOOLEAN ShowDownArrow
;
1139 BOOLEAN ShowUpArrow
;
1140 UINTN DimensionsWidth
;
1142 BOOLEAN OrderedList
;
1146 EFI_HII_VALUE HiiValue
;
1147 DISPLAY_QUESTION_OPTION
*OneOfOption
;
1148 DISPLAY_QUESTION_OPTION
*CurrentOption
;
1149 FORM_DISPLAY_ENGINE_STATEMENT
*Question
;
1151 EFI_IFR_ORDERED_LIST
*OrderList
;
1153 DimensionsWidth
= gStatementDimensions
.RightColumn
- gStatementDimensions
.LeftColumn
;
1157 CurrentOption
= NULL
;
1158 ShowDownArrow
= FALSE
;
1159 ShowUpArrow
= FALSE
;
1161 StringPtr
= AllocateZeroPool ((gOptionBlockWidth
+ 1) * 2);
1164 ZeroMem (&HiiValue
, sizeof (EFI_HII_VALUE
));
1166 Question
= MenuOption
->ThisTag
;
1167 if (Question
->OpCode
->OpCode
== EFI_IFR_ORDERED_LIST_OP
) {
1168 Link
= GetFirstNode (&Question
->OptionListHead
);
1169 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1170 ValueArray
= Question
->CurrentValue
.Buffer
;
1171 ValueType
= OneOfOption
->OptionOpCode
->Type
;
1173 OrderList
= (EFI_IFR_ORDERED_LIST
*) Question
->OpCode
;
1175 OrderedList
= FALSE
;
1180 // Calculate Option count
1184 AdjustOptionOrder(Question
, &PopUpMenuLines
);
1186 Link
= GetFirstNode (&Question
->OptionListHead
);
1187 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1188 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1190 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1195 // Get the number of one of options present and its size
1198 HighlightOptionIndex
= 0;
1199 Link
= GetFirstNode (&Question
->OptionListHead
);
1200 for (Index
= 0; Index
< PopUpMenuLines
; Index
++) {
1201 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1203 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1204 if (StrLen (StringPtr
) > PopUpWidth
) {
1205 PopUpWidth
= StrLen (StringPtr
);
1207 FreePool (StringPtr
);
1208 HiiValue
.Type
= OneOfOption
->OptionOpCode
->Type
;
1209 SetValuesByType (&HiiValue
.Value
, &OneOfOption
->OptionOpCode
->Value
, HiiValue
.Type
);
1210 if (!OrderedList
&& (CompareHiiValue (&Question
->CurrentValue
, &HiiValue
, &Result
, NULL
) == EFI_SUCCESS
) && (Result
== 0)) {
1212 // Find current selected Option for OneOf
1214 HighlightOptionIndex
= Index
;
1217 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1221 // Perform popup menu initialization.
1223 PopUpWidth
= PopUpWidth
+ POPUP_PAD_SPACE_COUNT
;
1225 SavedAttribute
= gST
->ConOut
->Mode
->Attribute
;
1226 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1228 if ((PopUpWidth
+ POPUP_FRAME_WIDTH
) > DimensionsWidth
) {
1229 PopUpWidth
= DimensionsWidth
- POPUP_FRAME_WIDTH
;
1232 Start
= (DimensionsWidth
- PopUpWidth
- POPUP_FRAME_WIDTH
) / 2 + gStatementDimensions
.LeftColumn
;
1233 End
= Start
+ PopUpWidth
+ POPUP_FRAME_WIDTH
;
1234 Top
= gStatementDimensions
.TopRow
;
1235 Bottom
= gStatementDimensions
.BottomRow
- 1;
1237 MenuLinesInView
= Bottom
- Top
- 1;
1238 if (MenuLinesInView
>= PopUpMenuLines
) {
1239 Top
= Top
+ (MenuLinesInView
- PopUpMenuLines
) / 2;
1240 Bottom
= Top
+ PopUpMenuLines
+ 1;
1242 ShowDownArrow
= TRUE
;
1245 if (HighlightOptionIndex
> (MenuLinesInView
- 1)) {
1246 TopOptionIndex
= HighlightOptionIndex
- MenuLinesInView
+ 1;
1253 // Clear that portion of the screen
1255 ClearLines (Start
, End
, Top
, Bottom
, GetPopupColor ());
1258 // Draw "One of" pop-up menu
1260 Character
= BOXDRAW_DOWN_RIGHT
;
1261 PrintCharAt (Start
, Top
, Character
);
1262 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1263 if ((ShowUpArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1264 Character
= GEOMETRICSHAPE_UP_TRIANGLE
;
1266 Character
= BOXDRAW_HORIZONTAL
;
1269 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1272 Character
= BOXDRAW_DOWN_LEFT
;
1273 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1274 Character
= BOXDRAW_VERTICAL
;
1275 for (Index
= Top
+ 1; Index
< Bottom
; Index
++) {
1276 PrintCharAt (Start
, Index
, Character
);
1277 PrintCharAt (End
- 1, Index
, Character
);
1281 // Move to top Option
1283 Link
= GetFirstNode (&Question
->OptionListHead
);
1284 for (Index
= 0; Index
< TopOptionIndex
; Index
++) {
1285 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1289 // Display the One of options
1292 for (Index
= TopOptionIndex
; (Index
< PopUpMenuLines
) && (Index2
< Bottom
); Index
++) {
1293 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1294 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1296 StringPtr
= GetToken (OneOfOption
->OptionOpCode
->Option
, gFormData
->HiiHandle
);
1297 ASSERT (StringPtr
!= NULL
);
1299 // If the string occupies multiple lines, truncate it to fit in one line,
1300 // and append a "..." for indication.
1302 if (StrLen (StringPtr
) > (PopUpWidth
- 1)) {
1303 TempStringPtr
= AllocateZeroPool (sizeof (CHAR16
) * (PopUpWidth
- 1));
1304 ASSERT ( TempStringPtr
!= NULL
);
1305 CopyMem (TempStringPtr
, StringPtr
, (sizeof (CHAR16
) * (PopUpWidth
- 5)));
1306 FreePool (StringPtr
);
1307 StringPtr
= TempStringPtr
;
1308 StrCat (StringPtr
, L
"...");
1311 if (Index
== HighlightOptionIndex
) {
1313 // Highlight the selected one
1315 CurrentOption
= OneOfOption
;
1317 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPickListColor ());
1318 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1319 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1321 gST
->ConOut
->SetAttribute (gST
->ConOut
, GetPopupColor ());
1322 PrintStringAt (Start
+ 2, Index2
, StringPtr
);
1326 FreePool (StringPtr
);
1329 Character
= BOXDRAW_UP_RIGHT
;
1330 PrintCharAt (Start
, Bottom
, Character
);
1331 for (Index
= Start
; Index
+ 2 < End
; Index
++) {
1332 if ((ShowDownArrow
) && ((Index
+ 1) == (Start
+ End
) / 2)) {
1333 Character
= GEOMETRICSHAPE_DOWN_TRIANGLE
;
1335 Character
= BOXDRAW_HORIZONTAL
;
1338 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1341 Character
= BOXDRAW_UP_LEFT
;
1342 PrintCharAt ((UINTN
)-1, (UINTN
)-1, Character
);
1345 // Get User selection
1347 Key
.UnicodeChar
= CHAR_NULL
;
1348 if ((gDirection
== SCAN_UP
) || (gDirection
== SCAN_DOWN
)) {
1349 Key
.ScanCode
= gDirection
;
1354 Status
= WaitForKeyStroke (&Key
);
1357 switch (Key
.UnicodeChar
) {
1360 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1362 // Highlight reaches the top of the popup window, scroll one menu item.
1365 ShowDownArrow
= TRUE
;
1368 if (TopOptionIndex
== 0) {
1369 ShowUpArrow
= FALSE
;
1372 if (HighlightOptionIndex
> 0) {
1373 HighlightOptionIndex
--;
1375 ASSERT (CurrentOption
!= NULL
);
1376 SwapListEntries (CurrentOption
->Link
.BackLink
, &CurrentOption
->Link
);
1383 // If an ordered list op-code, we will allow for a popup of +/- keys
1384 // to create an ordered list of items
1387 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1388 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1390 // Highlight reaches the bottom of the popup window, scroll one menu item.
1396 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1397 ShowDownArrow
= FALSE
;
1400 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1401 HighlightOptionIndex
++;
1403 ASSERT (CurrentOption
!= NULL
);
1404 SwapListEntries (&CurrentOption
->Link
, CurrentOption
->Link
.ForwardLink
);
1410 switch (Key
.ScanCode
) {
1413 if (Key
.ScanCode
== SCAN_UP
) {
1414 if ((TopOptionIndex
> 0) && (TopOptionIndex
== HighlightOptionIndex
)) {
1416 // Highlight reaches the top of the popup window, scroll one menu item.
1419 ShowDownArrow
= TRUE
;
1422 if (TopOptionIndex
== 0) {
1423 ShowUpArrow
= FALSE
;
1426 if (HighlightOptionIndex
> 0) {
1427 HighlightOptionIndex
--;
1430 if (((TopOptionIndex
+ MenuLinesInView
) < PopUpMenuLines
) &&
1431 (HighlightOptionIndex
== (TopOptionIndex
+ MenuLinesInView
- 1))) {
1433 // Highlight reaches the bottom of the popup window, scroll one menu item.
1439 if ((TopOptionIndex
+ MenuLinesInView
) == PopUpMenuLines
) {
1440 ShowDownArrow
= FALSE
;
1443 if (HighlightOptionIndex
< (PopUpMenuLines
- 1)) {
1444 HighlightOptionIndex
++;
1450 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);
1453 // Restore link list order for orderedlist
1456 HiiValue
.Type
= ValueType
;
1457 HiiValue
.Value
.u64
= 0;
1458 for (Index
= 0; Index
< OrderList
->MaxContainers
; Index
++) {
1459 HiiValue
.Value
.u64
= GetArrayData (ValueArray
, ValueType
, Index
);
1460 if (HiiValue
.Value
.u64
== 0) {
1464 OneOfOption
= ValueToOption (Question
, &HiiValue
);
1465 if (OneOfOption
== NULL
) {
1466 return EFI_NOT_FOUND
;
1469 RemoveEntryList (&OneOfOption
->Link
);
1470 InsertTailList (&Question
->OptionListHead
, &OneOfOption
->Link
);
1474 return EFI_DEVICE_ERROR
;
1482 case CHAR_CARRIAGE_RETURN
:
1484 // return the current selection
1487 ReturnValue
= AllocateZeroPool (Question
->CurrentValue
.BufferLen
);
1488 ASSERT (ReturnValue
!= NULL
);
1490 Link
= GetFirstNode (&Question
->OptionListHead
);
1491 while (!IsNull (&Question
->OptionListHead
, Link
)) {
1492 OneOfOption
= DISPLAY_QUESTION_OPTION_FROM_LINK (Link
);
1493 Link
= GetNextNode (&Question
->OptionListHead
, Link
);
1495 SetArrayData (ReturnValue
, ValueType
, Index
, OneOfOption
->OptionOpCode
->Value
.u64
);
1498 if (Index
> OrderList
->MaxContainers
) {
1502 if (CompareMem (ReturnValue
, ValueArray
, Question
->CurrentValue
.BufferLen
) == 0) {
1503 FreePool (ReturnValue
);
1504 return EFI_DEVICE_ERROR
;
1506 gUserInput
->InputValue
.Buffer
= ReturnValue
;
1507 gUserInput
->InputValue
.BufferLen
= Question
->CurrentValue
.BufferLen
;
1508 Status
= EFI_SUCCESS
;
1511 ASSERT (CurrentOption
!= NULL
);
1512 gUserInput
->InputValue
.Type
= CurrentOption
->OptionOpCode
->Type
;
1513 if (IsValuesEqual (&Question
->CurrentValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
)) {
1514 return EFI_DEVICE_ERROR
;
1516 SetValuesByType (&gUserInput
->InputValue
.Value
, &CurrentOption
->OptionOpCode
->Value
, gUserInput
->InputValue
.Type
);
1517 Status
= EFI_SUCCESS
;
1521 gST
->ConOut
->SetAttribute (gST
->ConOut
, SavedAttribute
);