]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c
Rollback patch 14537 & 14538, because patch 14537 is not tested by Laszlo Ersek,...
[mirror_edk2.git] / MdeModulePkg / Universal / SetupBrowserDxe / InputHandler.c
1 /** @file
2 Implementation for handling user input from the User Interfaces.
3
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
9
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.
12
13 **/
14
15 #include "Setup.h"
16
17
18 /**
19 Get string or password input from user.
20
21 @param MenuOption Pointer to the current input menu.
22 @param Prompt The prompt string shown on popup window.
23 @param StringPtr Old user input and destination for use input string.
24
25 @retval EFI_SUCCESS If string input is read successfully
26 @retval EFI_DEVICE_ERROR If operation fails
27
28 **/
29 EFI_STATUS
30 ReadString (
31 IN UI_MENU_OPTION *MenuOption,
32 IN CHAR16 *Prompt,
33 IN OUT CHAR16 *StringPtr
34 )
35 {
36 EFI_STATUS Status;
37 EFI_INPUT_KEY Key;
38 CHAR16 NullCharacter;
39 UINTN ScreenSize;
40 CHAR16 Space[2];
41 CHAR16 KeyPad[2];
42 CHAR16 *TempString;
43 CHAR16 *BufferedString;
44 UINTN Index;
45 UINTN Index2;
46 UINTN Count;
47 UINTN Start;
48 UINTN Top;
49 UINTN DimensionsWidth;
50 UINTN DimensionsHeight;
51 UINTN CurrentCursor;
52 BOOLEAN CursorVisible;
53 UINTN Minimum;
54 UINTN Maximum;
55 FORM_BROWSER_STATEMENT *Question;
56 BOOLEAN IsPassword;
57
58 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
59 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;
60
61 NullCharacter = CHAR_NULL;
62 ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);
63 Space[0] = L' ';
64 Space[1] = CHAR_NULL;
65
66 Question = MenuOption->ThisTag;
67 Minimum = (UINTN) Question->Minimum;
68 Maximum = (UINTN) Question->Maximum;
69
70 if (Question->Operand == EFI_IFR_PASSWORD_OP) {
71 IsPassword = TRUE;
72 } else {
73 IsPassword = FALSE;
74 }
75
76 TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));
77 ASSERT (TempString);
78
79 if (ScreenSize < (Maximum + 1)) {
80 ScreenSize = Maximum + 1;
81 }
82
83 if ((ScreenSize + 2) > DimensionsWidth) {
84 ScreenSize = DimensionsWidth - 2;
85 }
86
87 BufferedString = AllocateZeroPool (ScreenSize * 2);
88 ASSERT (BufferedString);
89
90 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;
91 Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;
92
93 //
94 // Display prompt for string
95 //
96 CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
97
98 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
99
100 CursorVisible = gST->ConOut->Mode->CursorVisible;
101 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
102
103 CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
104 if (CurrentCursor != 0) {
105 //
106 // Show the string which has beed saved before.
107 //
108 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
109 PrintStringAt (Start + 1, Top + 3, BufferedString);
110
111 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
112 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
113 } else {
114 Index = 0;
115 }
116
117 if (IsPassword) {
118 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
119 }
120
121 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
122 BufferedString[Count] = StringPtr[Index];
123
124 if (IsPassword) {
125 PrintChar (L'*');
126 }
127 }
128
129 if (!IsPassword) {
130 PrintStringAt (Start + 1, Top + 3, BufferedString);
131 }
132
133 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
134 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
135 }
136
137 do {
138 Status = WaitForKeyStroke (&Key);
139 ASSERT_EFI_ERROR (Status);
140
141 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
142 switch (Key.UnicodeChar) {
143 case CHAR_NULL:
144 switch (Key.ScanCode) {
145 case SCAN_LEFT:
146 if (CurrentCursor > 0) {
147 CurrentCursor--;
148 }
149 break;
150
151 case SCAN_RIGHT:
152 if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
153 CurrentCursor++;
154 }
155 break;
156
157 case SCAN_ESC:
158 FreePool (TempString);
159 FreePool (BufferedString);
160 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
161 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
162 return EFI_DEVICE_ERROR;
163
164 default:
165 break;
166 }
167
168 break;
169
170 case CHAR_CARRIAGE_RETURN:
171 if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
172
173 FreePool (TempString);
174 FreePool (BufferedString);
175 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
176 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
177 return EFI_SUCCESS;
178 } else {
179 //
180 // Simply create a popup to tell the user that they had typed in too few characters.
181 // To save code space, we can then treat this as an error and return back to the menu.
182 //
183 do {
184 CreateDialog (4, TRUE, 0, NULL, &Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);
185 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
186
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;
192 }
193
194 break;
195
196 case CHAR_BACKSPACE:
197 if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {
198 for (Index = 0; Index < CurrentCursor - 1; Index++) {
199 TempString[Index] = StringPtr[Index];
200 }
201 Count = GetStringWidth (StringPtr) / 2 - 1;
202 if (Count >= CurrentCursor) {
203 for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {
204 TempString[Index] = StringPtr[Index2];
205 }
206 TempString[Index] = CHAR_NULL;
207 }
208 //
209 // Effectively truncate string by 1 character
210 //
211 StrCpy (StringPtr, TempString);
212 CurrentCursor --;
213 }
214
215 default:
216 //
217 // If it is the beginning of the string, don't worry about checking maximum limits
218 //
219 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
220 StrnCpy (StringPtr, &Key.UnicodeChar, 1);
221 CurrentCursor++;
222 } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
223 KeyPad[0] = Key.UnicodeChar;
224 KeyPad[1] = CHAR_NULL;
225 Count = GetStringWidth (StringPtr) / 2 - 1;
226 if (CurrentCursor < Count) {
227 for (Index = 0; Index < CurrentCursor; Index++) {
228 TempString[Index] = StringPtr[Index];
229 }
230 TempString[Index] = CHAR_NULL;
231 StrCat (TempString, KeyPad);
232 StrCat (TempString, StringPtr + CurrentCursor);
233 StrCpy (StringPtr, TempString);
234 } else {
235 StrCat (StringPtr, KeyPad);
236 }
237 CurrentCursor++;
238 }
239
240 //
241 // If the width of the input string is now larger than the screen, we nee to
242 // adjust the index to start printing portions of the string
243 //
244 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
245 PrintStringAt (Start + 1, Top + 3, BufferedString);
246
247 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
248 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
249 } else {
250 Index = 0;
251 }
252
253 if (IsPassword) {
254 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
255 }
256
257 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
258 BufferedString[Count] = StringPtr[Index];
259
260 if (IsPassword) {
261 PrintChar (L'*');
262 }
263 }
264
265 if (!IsPassword) {
266 PrintStringAt (Start + 1, Top + 3, BufferedString);
267 }
268 break;
269 }
270
271 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
272 gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
273 } while (TRUE);
274
275 }
276
277 /**
278 Adjust the value to the correct one. Rules follow the sample:
279 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01
280 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28
281
282 @param Question Pointer to current question.
283 @param Sequence The sequence of the field in the question.
284 **/
285 VOID
286 AdjustQuestionValue (
287 IN FORM_BROWSER_STATEMENT *Question,
288 IN UINT8 Sequence
289 )
290 {
291 UINT8 Month;
292 UINT16 Year;
293 UINT8 Maximum;
294 UINT8 Minimum;
295
296 if (Question->Operand != EFI_IFR_DATE_OP) {
297 return;
298 }
299
300 Month = Question->HiiValue.Value.date.Month;
301 Year = Question->HiiValue.Value.date.Year;
302 Minimum = 1;
303
304 switch (Month) {
305 case 2:
306 if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {
307 Maximum = 29;
308 } else {
309 Maximum = 28;
310 }
311 break;
312 case 4:
313 case 6:
314 case 9:
315 case 11:
316 Maximum = 30;
317 break;
318 default:
319 Maximum = 31;
320 break;
321 }
322
323 //
324 // Change the month area.
325 //
326 if (Sequence == 0) {
327 if (Question->HiiValue.Value.date.Day > Maximum) {
328 Question->HiiValue.Value.date.Day = Maximum;
329 }
330 }
331
332 //
333 // Change the Year area.
334 //
335 if (Sequence == 2) {
336 if (Question->HiiValue.Value.date.Day > Maximum) {
337 Question->HiiValue.Value.date.Day = Minimum;
338 }
339 }
340 }
341
342 /**
343 This routine reads a numeric value from the user input.
344
345 @param Selection Pointer to current selection.
346 @param MenuOption Pointer to the current input menu.
347
348 @retval EFI_SUCCESS If numerical input is read successfully
349 @retval EFI_DEVICE_ERROR If operation fails
350
351 **/
352 EFI_STATUS
353 GetNumericInput (
354 IN UI_MENU_SELECTION *Selection,
355 IN UI_MENU_OPTION *MenuOption
356 )
357 {
358 EFI_STATUS Status;
359 UINTN Column;
360 UINTN Row;
361 CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];
362 CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
363 UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
364 UINTN Count;
365 UINTN Loop;
366 BOOLEAN ManualInput;
367 BOOLEAN HexInput;
368 BOOLEAN DateOrTime;
369 UINTN InputWidth;
370 UINT64 EditValue;
371 UINT64 Step;
372 UINT64 Minimum;
373 UINT64 Maximum;
374 UINTN EraseLen;
375 UINT8 Digital;
376 EFI_INPUT_KEY Key;
377 EFI_HII_VALUE *QuestionValue;
378 FORM_BROWSER_FORM *Form;
379 FORM_BROWSER_FORMSET *FormSet;
380 FORM_BROWSER_STATEMENT *Question;
381
382 Column = MenuOption->OptCol;
383 Row = MenuOption->Row;
384 PreviousNumber[0] = 0;
385 Count = 0;
386 InputWidth = 0;
387 Digital = 0;
388
389 FormSet = Selection->FormSet;
390 Form = Selection->Form;
391 Question = MenuOption->ThisTag;
392 QuestionValue = &Question->HiiValue;
393 Step = Question->Step;
394 Minimum = Question->Minimum;
395 Maximum = Question->Maximum;
396
397 //
398 // Only two case, user can enter to this function: Enter and +/- case.
399 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
400 //
401 ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
402
403 if ((Question->Operand == EFI_IFR_DATE_OP) || (Question->Operand == EFI_IFR_TIME_OP)) {
404 DateOrTime = TRUE;
405 } else {
406 DateOrTime = FALSE;
407 }
408
409 //
410 // Prepare Value to be edit
411 //
412 EraseLen = 0;
413 EditValue = 0;
414 if (Question->Operand == EFI_IFR_DATE_OP) {
415 Step = 1;
416 Minimum = 1;
417
418 switch (MenuOption->Sequence) {
419 case 0:
420 Maximum = 12;
421 EraseLen = 4;
422 EditValue = QuestionValue->Value.date.Month;
423 break;
424
425 case 1:
426 switch (QuestionValue->Value.date.Month) {
427 case 2:
428 if ((QuestionValue->Value.date.Year % 4) == 0 &&
429 ((QuestionValue->Value.date.Year % 100) != 0 ||
430 (QuestionValue->Value.date.Year % 400) == 0)) {
431 Maximum = 29;
432 } else {
433 Maximum = 28;
434 }
435 break;
436 case 4:
437 case 6:
438 case 9:
439 case 11:
440 Maximum = 30;
441 break;
442 default:
443 Maximum = 31;
444 break;
445 }
446
447 EraseLen = 3;
448 EditValue = QuestionValue->Value.date.Day;
449 break;
450
451 case 2:
452 Maximum = 0xffff;
453 EraseLen = 5;
454 EditValue = QuestionValue->Value.date.Year;
455 break;
456
457 default:
458 break;
459 }
460 } else if (Question->Operand == EFI_IFR_TIME_OP) {
461 Step = 1;
462 Minimum = 0;
463
464 switch (MenuOption->Sequence) {
465 case 0:
466 Maximum = 23;
467 EraseLen = 4;
468 EditValue = QuestionValue->Value.time.Hour;
469 break;
470
471 case 1:
472 Maximum = 59;
473 EraseLen = 3;
474 EditValue = QuestionValue->Value.time.Minute;
475 break;
476
477 case 2:
478 Maximum = 59;
479 EraseLen = 3;
480 EditValue = QuestionValue->Value.time.Second;
481 break;
482
483 default:
484 break;
485 }
486 } else {
487 //
488 // Numeric
489 //
490 EraseLen = gOptionBlockWidth;
491 EditValue = QuestionValue->Value.u64;
492 if (Maximum == 0) {
493 Maximum = (UINT64) -1;
494 }
495 }
496
497 if ((Question->Operand == EFI_IFR_NUMERIC_OP) &&
498 ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
499 HexInput = TRUE;
500 } else {
501 HexInput = FALSE;
502 }
503
504 //
505 // Enter from "Enter" input, clear the old word showing.
506 //
507 if (ManualInput) {
508 if (Question->Operand == EFI_IFR_NUMERIC_OP) {
509 if (HexInput) {
510 InputWidth = Question->StorageWidth * 2;
511 } else {
512 switch (Question->StorageWidth) {
513 case 1:
514 InputWidth = 3;
515 break;
516
517 case 2:
518 InputWidth = 5;
519 break;
520
521 case 4:
522 InputWidth = 10;
523 break;
524
525 case 8:
526 InputWidth = 20;
527 break;
528
529 default:
530 InputWidth = 0;
531 break;
532 }
533 }
534
535 InputText[0] = LEFT_NUMERIC_DELIMITER;
536 SetUnicodeMem (InputText + 1, InputWidth, L' ');
537 ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
538 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
539 InputText[InputWidth + 2] = L'\0';
540
541 PrintAt (Column, Row, InputText);
542 Column++;
543 }
544
545 if (Question->Operand == EFI_IFR_DATE_OP) {
546 if (MenuOption->Sequence == 2) {
547 InputWidth = 4;
548 } else {
549 InputWidth = 2;
550 }
551
552 if (MenuOption->Sequence == 0) {
553 InputText[0] = LEFT_NUMERIC_DELIMITER;
554 SetUnicodeMem (InputText + 1, InputWidth, L' ');
555 } else {
556 SetUnicodeMem (InputText, InputWidth, L' ');
557 }
558
559 if (MenuOption->Sequence == 2) {
560 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
561 } else {
562 InputText[InputWidth + 1] = DATE_SEPARATOR;
563 }
564 InputText[InputWidth + 2] = L'\0';
565
566 PrintAt (Column, Row, InputText);
567 if (MenuOption->Sequence == 0) {
568 Column++;
569 }
570 }
571
572 if (Question->Operand == EFI_IFR_TIME_OP) {
573 InputWidth = 2;
574
575 if (MenuOption->Sequence == 0) {
576 InputText[0] = LEFT_NUMERIC_DELIMITER;
577 SetUnicodeMem (InputText + 1, InputWidth, L' ');
578 } else {
579 SetUnicodeMem (InputText, InputWidth, L' ');
580 }
581
582 if (MenuOption->Sequence == 2) {
583 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
584 } else {
585 InputText[InputWidth + 1] = TIME_SEPARATOR;
586 }
587 InputText[InputWidth + 2] = L'\0';
588
589 PrintAt (Column, Row, InputText);
590 if (MenuOption->Sequence == 0) {
591 Column++;
592 }
593 }
594 }
595
596 //
597 // First time we enter this handler, we need to check to see if
598 // we were passed an increment or decrement directive
599 //
600 do {
601 Key.UnicodeChar = CHAR_NULL;
602 if (gDirection != 0) {
603 Key.ScanCode = gDirection;
604 gDirection = 0;
605 goto TheKey2;
606 }
607
608 Status = WaitForKeyStroke (&Key);
609
610 TheKey2:
611 switch (Key.UnicodeChar) {
612
613 case '+':
614 case '-':
615 if (Key.UnicodeChar == '+') {
616 Key.ScanCode = SCAN_RIGHT;
617 } else {
618 Key.ScanCode = SCAN_LEFT;
619 }
620 Key.UnicodeChar = CHAR_NULL;
621 goto TheKey2;
622
623 case CHAR_NULL:
624 switch (Key.ScanCode) {
625 case SCAN_LEFT:
626 case SCAN_RIGHT:
627 if (DateOrTime && !ManualInput) {
628 //
629 // By setting this value, we will return back to the caller.
630 // We need to do this since an auto-refresh will destroy the adjustment
631 // based on what the real-time-clock is showing. So we always commit
632 // upon changing the value.
633 //
634 gDirection = SCAN_DOWN;
635 }
636
637 if ((Step != 0) && !ManualInput) {
638 if (Key.ScanCode == SCAN_LEFT) {
639 if (EditValue >= Minimum + Step) {
640 EditValue = EditValue - Step;
641 } else if (EditValue > Minimum){
642 EditValue = Minimum;
643 } else {
644 EditValue = Maximum;
645 }
646 } else if (Key.ScanCode == SCAN_RIGHT) {
647 if (EditValue + Step <= Maximum) {
648 EditValue = EditValue + Step;
649 } else if (EditValue < Maximum) {
650 EditValue = Maximum;
651 } else {
652 EditValue = Minimum;
653 }
654 }
655
656 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
657 if (Question->Operand == EFI_IFR_DATE_OP) {
658 if (MenuOption->Sequence == 2) {
659 //
660 // Year
661 //
662 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
663 } else {
664 //
665 // Month/Day
666 //
667 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
668 }
669
670 if (MenuOption->Sequence == 0) {
671 ASSERT (EraseLen >= 2);
672 FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
673 } else if (MenuOption->Sequence == 1) {
674 ASSERT (EraseLen >= 1);
675 FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
676 }
677 } else if (Question->Operand == EFI_IFR_TIME_OP) {
678 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
679
680 if (MenuOption->Sequence == 0) {
681 ASSERT (EraseLen >= 2);
682 FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
683 } else if (MenuOption->Sequence == 1) {
684 ASSERT (EraseLen >= 1);
685 FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
686 }
687 } else {
688 QuestionValue->Value.u64 = EditValue;
689 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
690 }
691
692 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);
693 for (Loop = 0; Loop < EraseLen; Loop++) {
694 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
695 }
696 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));
697
698 if (MenuOption->Sequence == 0) {
699 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
700 Column = MenuOption->OptCol + 1;
701 }
702
703 PrintStringAt (Column, Row, FormattedNumber);
704
705 if (!DateOrTime || MenuOption->Sequence == 2) {
706 PrintChar (RIGHT_NUMERIC_DELIMITER);
707 }
708 }
709
710 goto EnterCarriageReturn;
711 break;
712
713 case SCAN_UP:
714 case SCAN_DOWN:
715 goto EnterCarriageReturn;
716
717 case SCAN_ESC:
718 return EFI_DEVICE_ERROR;
719
720 default:
721 break;
722 }
723
724 break;
725
726 EnterCarriageReturn:
727
728 case CHAR_CARRIAGE_RETURN:
729 //
730 // Validate input value with Minimum value.
731 //
732 if (EditValue < Minimum) {
733 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
734 break;
735 } else {
736 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
737 }
738
739 //
740 // Store Edit value back to Question
741 //
742 if (Question->Operand == EFI_IFR_DATE_OP) {
743 switch (MenuOption->Sequence) {
744 case 0:
745 QuestionValue->Value.date.Month = (UINT8) EditValue;
746 break;
747
748 case 1:
749 QuestionValue->Value.date.Day = (UINT8) EditValue;
750 break;
751
752 case 2:
753 QuestionValue->Value.date.Year = (UINT16) EditValue;
754 break;
755
756 default:
757 break;
758 }
759 } else if (Question->Operand == EFI_IFR_TIME_OP) {
760 switch (MenuOption->Sequence) {
761 case 0:
762 QuestionValue->Value.time.Hour = (UINT8) EditValue;
763 break;
764
765 case 1:
766 QuestionValue->Value.time.Minute = (UINT8) EditValue;
767 break;
768
769 case 2:
770 QuestionValue->Value.time.Second = (UINT8) EditValue;
771 break;
772
773 default:
774 break;
775 }
776 } else {
777 //
778 // Numeric
779 //
780 QuestionValue->Value.u64 = EditValue;
781 }
782
783 //
784 // Adjust the value to the correct one.
785 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
786 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
787 //
788 if (Question->Operand == EFI_IFR_DATE_OP &&
789 (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {
790 AdjustQuestionValue (Question, (UINT8)MenuOption->Sequence);
791 }
792
793 //
794 // Check to see if the Value is something reasonable against consistency limitations.
795 // If not, let's kick the error specified.
796 //
797 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
798 if (EFI_ERROR (Status)) {
799 //
800 // Input value is not valid, restore Question Value
801 //
802 GetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
803 } else {
804 SetQuestionValue (FormSet, Form, Question, GetSetValueWithEditBuffer);
805 if (!DateOrTime || (Question->Storage != NULL)) {
806 //
807 // NV flag is unnecessary for RTC type of Date/Time
808 //
809 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
810 }
811 }
812
813 return Status;
814 break;
815
816 case CHAR_BACKSPACE:
817 if (ManualInput) {
818 if (Count == 0) {
819 break;
820 }
821 //
822 // Remove a character
823 //
824 EditValue = PreviousNumber[Count - 1];
825 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
826 Count--;
827 Column--;
828 PrintAt (Column, Row, L" ");
829 }
830 break;
831
832 default:
833 if (ManualInput) {
834 if (HexInput) {
835 if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
836 Digital = (UINT8) (Key.UnicodeChar - L'0');
837 } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
838 Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);
839 } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
840 Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);
841 } else {
842 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
843 break;
844 }
845 } else {
846 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
847 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
848 break;
849 }
850 }
851
852 //
853 // If Count exceed input width, there is no way more is valid
854 //
855 if (Count >= InputWidth) {
856 break;
857 }
858 //
859 // Someone typed something valid!
860 //
861 if (Count != 0) {
862 if (HexInput) {
863 EditValue = LShiftU64 (EditValue, 4) + Digital;
864 } else {
865 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
866 }
867 } else {
868 if (HexInput) {
869 EditValue = Digital;
870 } else {
871 EditValue = Key.UnicodeChar - L'0';
872 }
873 }
874
875 if (EditValue > Maximum) {
876 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);
877 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));
878 EditValue = PreviousNumber[Count];
879 break;
880 } else {
881 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);
882 }
883
884 Count++;
885 ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));
886 PreviousNumber[Count] = EditValue;
887
888 PrintCharAt (Column, Row, Key.UnicodeChar);
889 Column++;
890 }
891 break;
892 }
893 } while (TRUE);
894
895 }
896
897
898 /**
899 Get selection for OneOf and OrderedList (Left/Right will be ignored).
900
901 @param Selection Pointer to current selection.
902 @param MenuOption Pointer to the current input menu.
903
904 @retval EFI_SUCCESS If Option input is processed successfully
905 @retval EFI_DEVICE_ERROR If operation fails
906
907 **/
908 EFI_STATUS
909 GetSelectionInputPopUp (
910 IN UI_MENU_SELECTION *Selection,
911 IN UI_MENU_OPTION *MenuOption
912 )
913 {
914 EFI_STATUS Status;
915 EFI_INPUT_KEY Key;
916 UINTN Index;
917 CHAR16 *StringPtr;
918 CHAR16 *TempStringPtr;
919 UINTN Index2;
920 UINTN TopOptionIndex;
921 UINTN HighlightOptionIndex;
922 UINTN Start;
923 UINTN End;
924 UINTN Top;
925 UINTN Bottom;
926 UINTN PopUpMenuLines;
927 UINTN MenuLinesInView;
928 UINTN PopUpWidth;
929 CHAR16 Character;
930 INT32 SavedAttribute;
931 BOOLEAN ShowDownArrow;
932 BOOLEAN ShowUpArrow;
933 UINTN DimensionsWidth;
934 LIST_ENTRY *Link;
935 BOOLEAN OrderedList;
936 UINT8 *ValueArray;
937 UINT8 ValueType;
938 EFI_HII_VALUE HiiValue;
939 EFI_HII_VALUE *HiiValueArray;
940 UINTN OptionCount;
941 QUESTION_OPTION *OneOfOption;
942 QUESTION_OPTION *CurrentOption;
943 FORM_BROWSER_STATEMENT *Question;
944 INTN Result;
945
946 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;
947
948 ValueArray = NULL;
949 ValueType = 0;
950 CurrentOption = NULL;
951 ShowDownArrow = FALSE;
952 ShowUpArrow = FALSE;
953
954 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
955 ASSERT (StringPtr);
956
957 Question = MenuOption->ThisTag;
958 if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {
959 ValueArray = Question->BufferValue;
960 ValueType = Question->ValueType;
961 OrderedList = TRUE;
962 } else {
963 OrderedList = FALSE;
964 }
965
966 //
967 // Calculate Option count
968 //
969 if (OrderedList) {
970 for (Index = 0; Index < Question->MaxContainers; Index++) {
971 if (GetArrayData (ValueArray, ValueType, Index) == 0) {
972 break;
973 }
974 }
975
976 OptionCount = Index;
977 } else {
978 OptionCount = 0;
979 Link = GetFirstNode (&Question->OptionListHead);
980 while (!IsNull (&Question->OptionListHead, Link)) {
981 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
982
983 OptionCount++;
984
985 Link = GetNextNode (&Question->OptionListHead, Link);
986 }
987 }
988
989 //
990 // Move valid Option to list head.
991 //
992 PopUpMenuLines = 0;
993 if (OrderedList) {
994 //
995 // Prepare HiiValue array
996 //
997 HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));
998 ASSERT (HiiValueArray != NULL);
999 for (Index = 0; Index < OptionCount; Index++) {
1000 HiiValueArray[Index].Type = ValueType;
1001 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1002 }
1003
1004 for (Index = 0; Index < OptionCount; Index++) {
1005 OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);
1006 if (OneOfOption == NULL) {
1007 return EFI_NOT_FOUND;
1008 }
1009
1010 RemoveEntryList (&OneOfOption->Link);
1011
1012 //
1013 // Insert to head.
1014 //
1015 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
1016
1017 PopUpMenuLines++;
1018 }
1019
1020 FreePool (HiiValueArray);
1021 } else {
1022 Link = GetFirstNode (&Question->OptionListHead);
1023 for (Index = 0; Index < OptionCount; Index++) {
1024 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
1025 Link = GetNextNode (&Question->OptionListHead, Link);
1026 if ((OneOfOption->SuppressExpression != NULL) &&
1027 EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {
1028 continue;
1029 } else {
1030 PopUpMenuLines++;
1031 }
1032 }
1033 }
1034
1035 //
1036 // Get the number of one of options present and its size
1037 //
1038 PopUpWidth = 0;
1039 HighlightOptionIndex = 0;
1040 Link = GetFirstNode (&Question->OptionListHead);
1041 for (Index = 0; Index < PopUpMenuLines; Index++) {
1042 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
1043 Link = GetNextNode (&Question->OptionListHead, Link);
1044
1045 if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&
1046 EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {
1047 Index--;
1048 continue;
1049 }
1050
1051 StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
1052 if (StrLen (StringPtr) > PopUpWidth) {
1053 PopUpWidth = StrLen (StringPtr);
1054 }
1055 FreePool (StringPtr);
1056
1057 if (!OrderedList && (CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
1058 //
1059 // Find current selected Option for OneOf
1060 //
1061 HighlightOptionIndex = Index;
1062 }
1063 }
1064
1065 //
1066 // Perform popup menu initialization.
1067 //
1068 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
1069
1070 SavedAttribute = gST->ConOut->Mode->Attribute;
1071 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
1072
1073 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
1074 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
1075 }
1076
1077 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;
1078 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;
1079 Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;
1080 Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - gFooterHeight - 1;
1081
1082 MenuLinesInView = Bottom - Top - 1;
1083 if (MenuLinesInView >= PopUpMenuLines) {
1084 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
1085 Bottom = Top + PopUpMenuLines + 1;
1086 } else {
1087 ShowDownArrow = TRUE;
1088 }
1089
1090 if (HighlightOptionIndex > (MenuLinesInView - 1)) {
1091 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
1092 } else {
1093 TopOptionIndex = 0;
1094 }
1095
1096 do {
1097 //
1098 // Clear that portion of the screen
1099 //
1100 ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);
1101
1102 //
1103 // Draw "One of" pop-up menu
1104 //
1105 Character = BOXDRAW_DOWN_RIGHT;
1106 PrintCharAt (Start, Top, Character);
1107 for (Index = Start; Index + 2 < End; Index++) {
1108 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
1109 Character = GEOMETRICSHAPE_UP_TRIANGLE;
1110 } else {
1111 Character = BOXDRAW_HORIZONTAL;
1112 }
1113
1114 PrintChar (Character);
1115 }
1116
1117 Character = BOXDRAW_DOWN_LEFT;
1118 PrintChar (Character);
1119 Character = BOXDRAW_VERTICAL;
1120 for (Index = Top + 1; Index < Bottom; Index++) {
1121 PrintCharAt (Start, Index, Character);
1122 PrintCharAt (End - 1, Index, Character);
1123 }
1124
1125 //
1126 // Move to top Option
1127 //
1128 Link = GetFirstNode (&Question->OptionListHead);
1129 for (Index = 0; Index < TopOptionIndex; Index++) {
1130 Link = GetNextNode (&Question->OptionListHead, Link);
1131
1132 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
1133 if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&
1134 EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {
1135 Index--;
1136 continue;
1137 }
1138 }
1139
1140 //
1141 // Display the One of options
1142 //
1143 Index2 = Top + 1;
1144 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
1145 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
1146 Link = GetNextNode (&Question->OptionListHead, Link);
1147
1148 if (!OrderedList && (OneOfOption->SuppressExpression != NULL) &&
1149 EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) > ExpressFalse) {
1150 Index--;
1151 continue;
1152 }
1153
1154 StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);
1155 ASSERT (StringPtr != NULL);
1156 //
1157 // If the string occupies multiple lines, truncate it to fit in one line,
1158 // and append a "..." for indication.
1159 //
1160 if (StrLen (StringPtr) > (PopUpWidth - 1)) {
1161 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
1162 ASSERT ( TempStringPtr != NULL );
1163 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
1164 FreePool (StringPtr);
1165 StringPtr = TempStringPtr;
1166 StrCat (StringPtr, L"...");
1167 }
1168
1169 if (Index == HighlightOptionIndex) {
1170 //
1171 // Highlight the selected one
1172 //
1173 CurrentOption = OneOfOption;
1174
1175 gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);
1176 PrintStringAt (Start + 2, Index2, StringPtr);
1177 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
1178 } else {
1179 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);
1180 PrintStringAt (Start + 2, Index2, StringPtr);
1181 }
1182
1183 Index2++;
1184 FreePool (StringPtr);
1185 }
1186
1187 Character = BOXDRAW_UP_RIGHT;
1188 PrintCharAt (Start, Bottom, Character);
1189 for (Index = Start; Index + 2 < End; Index++) {
1190 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
1191 Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
1192 } else {
1193 Character = BOXDRAW_HORIZONTAL;
1194 }
1195
1196 PrintChar (Character);
1197 }
1198
1199 Character = BOXDRAW_UP_LEFT;
1200 PrintChar (Character);
1201
1202 //
1203 // Get User selection
1204 //
1205 Key.UnicodeChar = CHAR_NULL;
1206 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
1207 Key.ScanCode = gDirection;
1208 gDirection = 0;
1209 goto TheKey;
1210 }
1211
1212 Status = WaitForKeyStroke (&Key);
1213
1214 TheKey:
1215 switch (Key.UnicodeChar) {
1216 case '+':
1217 if (OrderedList) {
1218 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1219 //
1220 // Highlight reaches the top of the popup window, scroll one menu item.
1221 //
1222 TopOptionIndex--;
1223 ShowDownArrow = TRUE;
1224 }
1225
1226 if (TopOptionIndex == 0) {
1227 ShowUpArrow = FALSE;
1228 }
1229
1230 if (HighlightOptionIndex > 0) {
1231 HighlightOptionIndex--;
1232
1233 ASSERT (CurrentOption != NULL);
1234 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
1235 }
1236 }
1237 break;
1238
1239 case '-':
1240 //
1241 // If an ordered list op-code, we will allow for a popup of +/- keys
1242 // to create an ordered list of items
1243 //
1244 if (OrderedList) {
1245 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1246 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
1247 //
1248 // Highlight reaches the bottom of the popup window, scroll one menu item.
1249 //
1250 TopOptionIndex++;
1251 ShowUpArrow = TRUE;
1252 }
1253
1254 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1255 ShowDownArrow = FALSE;
1256 }
1257
1258 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1259 HighlightOptionIndex++;
1260
1261 ASSERT (CurrentOption != NULL);
1262 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
1263 }
1264 }
1265 break;
1266
1267 case CHAR_NULL:
1268 switch (Key.ScanCode) {
1269 case SCAN_UP:
1270 case SCAN_DOWN:
1271 if (Key.ScanCode == SCAN_UP) {
1272 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1273 //
1274 // Highlight reaches the top of the popup window, scroll one menu item.
1275 //
1276 TopOptionIndex--;
1277 ShowDownArrow = TRUE;
1278 }
1279
1280 if (TopOptionIndex == 0) {
1281 ShowUpArrow = FALSE;
1282 }
1283
1284 if (HighlightOptionIndex > 0) {
1285 HighlightOptionIndex--;
1286 }
1287 } else {
1288 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1289 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
1290 //
1291 // Highlight reaches the bottom of the popup window, scroll one menu item.
1292 //
1293 TopOptionIndex++;
1294 ShowUpArrow = TRUE;
1295 }
1296
1297 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1298 ShowDownArrow = FALSE;
1299 }
1300
1301 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1302 HighlightOptionIndex++;
1303 }
1304 }
1305 break;
1306
1307 case SCAN_ESC:
1308 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1309
1310 //
1311 // Restore link list order for orderedlist
1312 //
1313 if (OrderedList) {
1314 HiiValue.Type = ValueType;
1315 HiiValue.Value.u64 = 0;
1316 for (Index = 0; Index < Question->MaxContainers; Index++) {
1317 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1318 if (HiiValue.Value.u64 == 0) {
1319 break;
1320 }
1321
1322 OneOfOption = ValueToOption (Question, &HiiValue);
1323 if (OneOfOption == NULL) {
1324 return EFI_NOT_FOUND;
1325 }
1326
1327 RemoveEntryList (&OneOfOption->Link);
1328 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
1329 }
1330 }
1331
1332 return EFI_DEVICE_ERROR;
1333
1334 default:
1335 break;
1336 }
1337
1338 break;
1339
1340 case CHAR_CARRIAGE_RETURN:
1341 //
1342 // return the current selection
1343 //
1344 if (OrderedList) {
1345 Index = 0;
1346 Link = GetFirstNode (&Question->OptionListHead);
1347 while (!IsNull (&Question->OptionListHead, Link)) {
1348 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);
1349 Link = GetNextNode (&Question->OptionListHead, Link);
1350
1351 if ((OneOfOption->SuppressExpression != NULL) &&
1352 EvaluateExpressionList(OneOfOption->SuppressExpression, FALSE, NULL, NULL) != ExpressFalse) {
1353 continue;
1354 }
1355
1356 SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);
1357
1358 Index++;
1359 if (Index > Question->MaxContainers) {
1360 break;
1361 }
1362 }
1363 } else {
1364 ASSERT (CurrentOption != NULL);
1365 CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));
1366 }
1367
1368 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1369
1370 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);
1371 if (EFI_ERROR (Status)) {
1372 //
1373 // Input value is not valid, restore Question Value
1374 //
1375 GetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
1376 } else {
1377 SetQuestionValue (Selection->FormSet, Selection->Form, Question, GetSetValueWithEditBuffer);
1378 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);
1379 }
1380
1381 return Status;
1382
1383 default:
1384 break;
1385 }
1386 } while (TRUE);
1387
1388 }
1389
1390 /**
1391 Wait for a key to be pressed by user.
1392
1393 @param Key The key which is pressed by user.
1394
1395 @retval EFI_SUCCESS The function always completed successfully.
1396
1397 **/
1398 EFI_STATUS
1399 WaitForKeyStroke (
1400 OUT EFI_INPUT_KEY *Key
1401 )
1402 {
1403 EFI_STATUS Status;
1404
1405 while (TRUE) {
1406 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);
1407 if (!EFI_ERROR (Status)) {
1408 break;
1409 }
1410
1411 if (Status != EFI_NOT_READY) {
1412 continue;
1413 }
1414
1415 UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0);
1416 }
1417 return Status;
1418 }