TianoCore EDK2 master
Loading...
Searching...
No Matches
InputHandler.c
Go to the documentation of this file.
1
10#include "FormDisplay.h"
11
20VOID
22 IN EFI_IFR_OP_HEADER *OpCode,
23 OUT UINTN *Minimum,
24 OUT UINTN *Maximum
25 )
26{
27 EFI_IFR_STRING *StringOp;
28 EFI_IFR_PASSWORD *PasswordOp;
29
30 if (OpCode->OpCode == EFI_IFR_STRING_OP) {
31 StringOp = (EFI_IFR_STRING *)OpCode;
32 *Minimum = StringOp->MinSize;
33 *Maximum = StringOp->MaxSize;
34 } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
35 PasswordOp = (EFI_IFR_PASSWORD *)OpCode;
36 *Minimum = PasswordOp->MinSize;
37 *Maximum = PasswordOp->MaxSize;
38 } else {
39 *Minimum = 0;
40 *Maximum = 0;
41 }
42}
43
57 IN UI_MENU_OPTION *MenuOption,
58 IN CHAR16 *Prompt,
59 IN OUT CHAR16 *StringPtr
60 )
61{
62 EFI_STATUS Status;
63 EFI_INPUT_KEY Key;
64 CHAR16 NullCharacter;
65 UINTN ScreenSize;
66 CHAR16 Space[2];
67 CHAR16 KeyPad[2];
68 CHAR16 *TempString;
69 CHAR16 *BufferedString;
70 UINTN Index;
71 UINTN Index2;
72 UINTN Count;
73 UINTN Start;
74 UINTN Top;
75 UINTN DimensionsWidth;
76 UINTN DimensionsHeight;
77 UINTN CurrentCursor;
78 BOOLEAN CursorVisible;
79 UINTN Minimum;
80 UINTN Maximum;
82 BOOLEAN IsPassword;
83 UINTN MaxLen;
84
85 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
86 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
87
88 NullCharacter = CHAR_NULL;
89 ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);
90 Space[0] = L' ';
91 Space[1] = CHAR_NULL;
92
93 Question = MenuOption->ThisTag;
94 GetFieldFromOp (Question->OpCode, &Minimum, &Maximum);
95
96 if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
97 IsPassword = TRUE;
98 } else {
99 IsPassword = FALSE;
100 }
101
102 MaxLen = Maximum + 1;
103 TempString = AllocateZeroPool (MaxLen * sizeof (CHAR16));
104 ASSERT (TempString);
105
106 if (ScreenSize < (Maximum + 1)) {
107 ScreenSize = Maximum + 1;
108 }
109
110 if ((ScreenSize + 2) > DimensionsWidth) {
111 ScreenSize = DimensionsWidth - 2;
112 }
113
114 BufferedString = AllocateZeroPool (ScreenSize * 2);
115 ASSERT (BufferedString);
116
117 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;
118 Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;
119
120 //
121 // Display prompt for string
122 //
123 // CreateDialog (NULL, "", Prompt, Space, "", NULL);
124 CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);
125 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
126
127 CursorVisible = gST->ConOut->Mode->CursorVisible;
128 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
129
130 CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
131 if (CurrentCursor != 0) {
132 //
133 // Show the string which has beed saved before.
134 //
135 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
136 PrintStringAt (Start + 1, Top + 3, BufferedString);
137
138 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
139 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
140 } else {
141 Index = 0;
142 }
143
144 if (IsPassword) {
145 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
146 }
147
148 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
149 BufferedString[Count] = StringPtr[Index];
150
151 if (IsPassword) {
152 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
153 }
154 }
155
156 if (!IsPassword) {
157 PrintStringAt (Start + 1, Top + 3, BufferedString);
158 }
159
160 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
161 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);
162 }
163
164 do {
165 Status = WaitForKeyStroke (&Key);
166 ASSERT_EFI_ERROR (Status);
167
168 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
169 switch (Key.UnicodeChar) {
170 case CHAR_NULL:
171 switch (Key.ScanCode) {
172 case SCAN_LEFT:
173 if (CurrentCursor > 0) {
174 CurrentCursor--;
175 }
176
177 break;
178
179 case SCAN_RIGHT:
180 if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
181 CurrentCursor++;
182 }
183
184 break;
185
186 case SCAN_ESC:
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 case SCAN_DELETE:
194 for (Index = CurrentCursor; StringPtr[Index] != CHAR_NULL; Index++) {
195 StringPtr[Index] = StringPtr[Index + 1];
196 PrintCharAt (Start + Index + 1, Top + 3, IsPassword && StringPtr[Index] != CHAR_NULL ? L'*' : StringPtr[Index]);
197 }
198
199 break;
200
201 default:
202 break;
203 }
204
205 break;
206
207 case CHAR_CARRIAGE_RETURN:
208 if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
209 FreePool (TempString);
210 FreePool (BufferedString);
211 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
212 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
213 return EFI_SUCCESS;
214 } else {
215 //
216 // Simply create a popup to tell the user that they had typed in too few characters.
217 // To save code space, we can then treat this as an error and return back to the menu.
218 //
219 do {
220 CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);
221 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
222
223 FreePool (TempString);
224 FreePool (BufferedString);
225 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
226 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);
227 return EFI_DEVICE_ERROR;
228 }
229
230 case CHAR_BACKSPACE:
231 if ((StringPtr[0] != CHAR_NULL) && (CurrentCursor != 0)) {
232 for (Index = 0; Index < CurrentCursor - 1; Index++) {
233 TempString[Index] = StringPtr[Index];
234 }
235
236 Count = GetStringWidth (StringPtr) / 2 - 1;
237 if (Count >= CurrentCursor) {
238 for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {
239 TempString[Index] = StringPtr[Index2];
240 }
241
242 TempString[Index] = CHAR_NULL;
243 }
244
245 //
246 // Effectively truncate string by 1 character
247 //
248 StrCpyS (StringPtr, MaxLen, TempString);
249 CurrentCursor--;
250 }
251
252 default:
253 //
254 // If it is the beginning of the string, don't worry about checking maximum limits
255 //
256 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
257 StrnCpyS (StringPtr, MaxLen, &Key.UnicodeChar, 1);
258 CurrentCursor++;
259 } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
260 KeyPad[0] = Key.UnicodeChar;
261 KeyPad[1] = CHAR_NULL;
262 Count = GetStringWidth (StringPtr) / 2 - 1;
263 if (CurrentCursor < Count) {
264 for (Index = 0; Index < CurrentCursor; Index++) {
265 TempString[Index] = StringPtr[Index];
266 }
267
268 TempString[Index] = CHAR_NULL;
269 StrCatS (TempString, MaxLen, KeyPad);
270 StrCatS (TempString, MaxLen, StringPtr + CurrentCursor);
271 StrCpyS (StringPtr, MaxLen, TempString);
272 } else {
273 StrCatS (StringPtr, MaxLen, KeyPad);
274 }
275
276 CurrentCursor++;
277 }
278
279 //
280 // If the width of the input string is now larger than the screen, we nee to
281 // adjust the index to start printing portions of the string
282 //
283 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
284 PrintStringAt (Start + 1, Top + 3, BufferedString);
285
286 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
287 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
288 } else {
289 Index = 0;
290 }
291
292 if (IsPassword) {
293 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
294 }
295
296 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
297 BufferedString[Count] = StringPtr[Index];
298
299 if (IsPassword) {
300 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
301 }
302 }
303
304 if (!IsPassword) {
305 PrintStringAt (Start + 1, Top + 3, BufferedString);
306 }
307
308 break;
309 }
310
311 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
312 gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
313 } while (TRUE);
314}
315
324VOID
326 IN EFI_HII_VALUE *QuestionValue,
327 IN UINT8 Sequence
328 )
329{
330 UINT8 Month;
331 UINT16 Year;
332 UINT8 Maximum;
333 UINT8 Minimum;
334
335 Month = QuestionValue->Value.date.Month;
336 Year = QuestionValue->Value.date.Year;
337 Minimum = 1;
338
339 switch (Month) {
340 case 2:
341 if (((Year % 4) == 0) && (((Year % 100) != 0) || ((Year % 400) == 0))) {
342 Maximum = 29;
343 } else {
344 Maximum = 28;
345 }
346
347 break;
348 case 4:
349 case 6:
350 case 9:
351 case 11:
352 Maximum = 30;
353 break;
354 default:
355 Maximum = 31;
356 break;
357 }
358
359 //
360 // Change the month area.
361 //
362 if (Sequence == 0) {
363 if (QuestionValue->Value.date.Day > Maximum) {
364 QuestionValue->Value.date.Day = Maximum;
365 }
366 }
367
368 //
369 // Change the Year area.
370 //
371 if (Sequence == 2) {
372 if (QuestionValue->Value.date.Day > Maximum) {
373 QuestionValue->Value.date.Day = Minimum;
374 }
375 }
376}
377
391VOID
393 IN EFI_IFR_OP_HEADER *OpCode,
394 IN BOOLEAN IntInput,
395 IN EFI_HII_VALUE *QuestionValue,
396 OUT UINT64 *Value,
397 OUT UINT64 *Minimum,
398 OUT UINT64 *Maximum,
399 OUT UINT64 *Step,
400 OUT UINT16 *StorageWidth
401 )
402{
403 EFI_IFR_NUMERIC *NumericOp;
404
405 NumericOp = (EFI_IFR_NUMERIC *)OpCode;
406
407 switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {
408 case EFI_IFR_NUMERIC_SIZE_1:
409 if (IntInput) {
410 *Minimum = (INT64)(INT8)NumericOp->data.u8.MinValue;
411 *Maximum = (INT64)(INT8)NumericOp->data.u8.MaxValue;
412 *Value = (INT64)(INT8)QuestionValue->Value.u8;
413 } else {
414 *Minimum = NumericOp->data.u8.MinValue;
415 *Maximum = NumericOp->data.u8.MaxValue;
416 *Value = QuestionValue->Value.u8;
417 }
418
419 *Step = NumericOp->data.u8.Step;
420 *StorageWidth = (UINT16)sizeof (UINT8);
421 break;
422
423 case EFI_IFR_NUMERIC_SIZE_2:
424 if (IntInput) {
425 *Minimum = (INT64)(INT16)NumericOp->data.u16.MinValue;
426 *Maximum = (INT64)(INT16)NumericOp->data.u16.MaxValue;
427 *Value = (INT64)(INT16)QuestionValue->Value.u16;
428 } else {
429 *Minimum = NumericOp->data.u16.MinValue;
430 *Maximum = NumericOp->data.u16.MaxValue;
431 *Value = QuestionValue->Value.u16;
432 }
433
434 *Step = NumericOp->data.u16.Step;
435 *StorageWidth = (UINT16)sizeof (UINT16);
436 break;
437
438 case EFI_IFR_NUMERIC_SIZE_4:
439 if (IntInput) {
440 *Minimum = (INT64)(INT32)NumericOp->data.u32.MinValue;
441 *Maximum = (INT64)(INT32)NumericOp->data.u32.MaxValue;
442 *Value = (INT64)(INT32)QuestionValue->Value.u32;
443 } else {
444 *Minimum = NumericOp->data.u32.MinValue;
445 *Maximum = NumericOp->data.u32.MaxValue;
446 *Value = QuestionValue->Value.u32;
447 }
448
449 *Step = NumericOp->data.u32.Step;
450 *StorageWidth = (UINT16)sizeof (UINT32);
451 break;
452
453 case EFI_IFR_NUMERIC_SIZE_8:
454 if (IntInput) {
455 *Minimum = (INT64)NumericOp->data.u64.MinValue;
456 *Maximum = (INT64)NumericOp->data.u64.MaxValue;
457 *Value = (INT64)QuestionValue->Value.u64;
458 } else {
459 *Minimum = NumericOp->data.u64.MinValue;
460 *Maximum = NumericOp->data.u64.MaxValue;
461 *Value = QuestionValue->Value.u64;
462 }
463
464 *Step = NumericOp->data.u64.Step;
465 *StorageWidth = (UINT16)sizeof (UINT64);
466 break;
467
468 default:
469 break;
470 }
471
472 if (*Maximum == 0) {
473 *Maximum = (UINT64)-1;
474 }
475}
476
488 IN UI_MENU_OPTION *MenuOption
489 )
490{
491 UINTN Column;
492 UINTN Row;
493 CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];
494 CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
495 UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
496 UINTN Count;
497 UINTN Loop;
498 BOOLEAN ManualInput;
499 BOOLEAN HexInput;
500 BOOLEAN IntInput;
501 BOOLEAN Negative;
502 BOOLEAN ValidateFail;
503 BOOLEAN DateOrTime;
504 UINTN InputWidth;
505 UINT64 EditValue;
506 UINT64 Step;
507 UINT64 Minimum;
508 UINT64 Maximum;
509 UINTN EraseLen;
510 UINT8 Digital;
511 EFI_INPUT_KEY Key;
512 EFI_HII_VALUE *QuestionValue;
514 EFI_IFR_NUMERIC *NumericOp;
515 UINT16 StorageWidth;
516
517 Column = MenuOption->OptCol;
518 Row = MenuOption->Row;
519 PreviousNumber[0] = 0;
520 Count = 0;
521 InputWidth = 0;
522 Digital = 0;
523 StorageWidth = 0;
524 Minimum = 0;
525 Maximum = 0;
526 NumericOp = NULL;
527 IntInput = FALSE;
528 HexInput = FALSE;
529 Negative = FALSE;
530 ValidateFail = FALSE;
531
532 Question = MenuOption->ThisTag;
533 QuestionValue = &Question->CurrentValue;
534 ZeroMem (InputText, MAX_NUMERIC_INPUT_WIDTH * sizeof (CHAR16));
535
536 //
537 // Only two case, user can enter to this function: Enter and +/- case.
538 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT
539 //
540 ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
541
542 if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
543 DateOrTime = TRUE;
544 } else {
545 DateOrTime = FALSE;
546 }
547
548 //
549 // Prepare Value to be edit
550 //
551 EraseLen = 0;
552 EditValue = 0;
553 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
554 Step = 1;
555 Minimum = 1;
556
557 switch (MenuOption->Sequence) {
558 case 0:
559 Maximum = 12;
560 EraseLen = 4;
561 EditValue = QuestionValue->Value.date.Month;
562 break;
563
564 case 1:
565 switch (QuestionValue->Value.date.Month) {
566 case 2:
567 if (((QuestionValue->Value.date.Year % 4) == 0) &&
568 (((QuestionValue->Value.date.Year % 100) != 0) ||
569 ((QuestionValue->Value.date.Year % 400) == 0)))
570 {
571 Maximum = 29;
572 } else {
573 Maximum = 28;
574 }
575
576 break;
577 case 4:
578 case 6:
579 case 9:
580 case 11:
581 Maximum = 30;
582 break;
583 default:
584 Maximum = 31;
585 break;
586 }
587
588 EraseLen = 3;
589 EditValue = QuestionValue->Value.date.Day;
590 break;
591
592 case 2:
593 Maximum = 0xffff;
594 EraseLen = 5;
595 EditValue = QuestionValue->Value.date.Year;
596 break;
597
598 default:
599 break;
600 }
601 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
602 Step = 1;
603 Minimum = 0;
604
605 switch (MenuOption->Sequence) {
606 case 0:
607 Maximum = 23;
608 EraseLen = 4;
609 EditValue = QuestionValue->Value.time.Hour;
610 break;
611
612 case 1:
613 Maximum = 59;
614 EraseLen = 3;
615 EditValue = QuestionValue->Value.time.Minute;
616 break;
617
618 case 2:
619 Maximum = 59;
620 EraseLen = 3;
621 EditValue = QuestionValue->Value.time.Second;
622 break;
623
624 default:
625 break;
626 }
627 } else {
628 ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);
629 NumericOp = (EFI_IFR_NUMERIC *)Question->OpCode;
630 GetValueFromNum (Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);
631 EraseLen = gOptionBlockWidth;
632 }
633
634 if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {
635 if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX) {
636 HexInput = TRUE;
637 } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0) {
638 //
639 // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.
640 //
641 IntInput = TRUE;
642 }
643 }
644
645 //
646 // Enter from "Enter" input, clear the old word showing.
647 //
648 if (ManualInput) {
649 if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
650 if (HexInput) {
651 InputWidth = StorageWidth * 2;
652 } else {
653 switch (StorageWidth) {
654 case 1:
655 InputWidth = 3;
656 break;
657
658 case 2:
659 InputWidth = 5;
660 break;
661
662 case 4:
663 InputWidth = 10;
664 break;
665
666 case 8:
667 InputWidth = 20;
668 break;
669
670 default:
671 InputWidth = 0;
672 break;
673 }
674
675 if (IntInput) {
676 //
677 // Support an extra '-' for negative number.
678 //
679 InputWidth += 1;
680 }
681 }
682
683 InputText[0] = LEFT_NUMERIC_DELIMITER;
684 SetUnicodeMem (InputText + 1, InputWidth, L' ');
685 ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);
686 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
687 InputText[InputWidth + 2] = L'\0';
688
689 PrintStringAt (Column, Row, InputText);
690 Column++;
691 }
692
693 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
694 if (MenuOption->Sequence == 2) {
695 InputWidth = 4;
696 } else {
697 InputWidth = 2;
698 }
699
700 if (MenuOption->Sequence == 0) {
701 InputText[0] = LEFT_NUMERIC_DELIMITER;
702 SetUnicodeMem (InputText + 1, InputWidth, L' ');
703 InputText[InputWidth + 1] = DATE_SEPARATOR;
704 InputText[InputWidth + 2] = L'\0';
705 } else if (MenuOption->Sequence == 1) {
706 SetUnicodeMem (InputText, InputWidth, L' ');
707 InputText[InputWidth] = DATE_SEPARATOR;
708 InputText[InputWidth + 1] = L'\0';
709 } else {
710 SetUnicodeMem (InputText, InputWidth, L' ');
711 InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
712 InputText[InputWidth + 1] = L'\0';
713 }
714
715 PrintStringAt (Column, Row, InputText);
716 if (MenuOption->Sequence == 0) {
717 Column++;
718 }
719 }
720
721 if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
722 InputWidth = 2;
723
724 if (MenuOption->Sequence == 0) {
725 InputText[0] = LEFT_NUMERIC_DELIMITER;
726 SetUnicodeMem (InputText + 1, InputWidth, L' ');
727 InputText[InputWidth + 1] = TIME_SEPARATOR;
728 InputText[InputWidth + 2] = L'\0';
729 } else if (MenuOption->Sequence == 1) {
730 SetUnicodeMem (InputText, InputWidth, L' ');
731 InputText[InputWidth] = TIME_SEPARATOR;
732 InputText[InputWidth + 1] = L'\0';
733 } else {
734 SetUnicodeMem (InputText, InputWidth, L' ');
735 InputText[InputWidth] = RIGHT_NUMERIC_DELIMITER;
736 InputText[InputWidth + 1] = L'\0';
737 }
738
739 PrintStringAt (Column, Row, InputText);
740 if (MenuOption->Sequence == 0) {
741 Column++;
742 }
743 }
744 }
745
746 //
747 // First time we enter this handler, we need to check to see if
748 // we were passed an increment or decrement directive
749 //
750 do {
751 Key.UnicodeChar = CHAR_NULL;
752 if (gDirection != 0) {
753 Key.ScanCode = gDirection;
754 gDirection = 0;
755 goto TheKey2;
756 }
757
758 WaitForKeyStroke (&Key);
759
760TheKey2:
761 switch (Key.UnicodeChar) {
762 case '+':
763 case '-':
764 if (ManualInput && IntInput) {
765 //
766 // In Manual input mode, check whether input the negative flag.
767 //
768 if (Key.UnicodeChar == '-') {
769 if (Negative) {
770 break;
771 }
772
773 Negative = TRUE;
774 PrintCharAt (Column++, Row, Key.UnicodeChar);
775 }
776 } else {
777 if (Key.UnicodeChar == '+') {
778 Key.ScanCode = SCAN_RIGHT;
779 } else {
780 Key.ScanCode = SCAN_LEFT;
781 }
782
783 Key.UnicodeChar = CHAR_NULL;
784 goto TheKey2;
785 }
786
787 break;
788
789 case CHAR_NULL:
790 switch (Key.ScanCode) {
791 case SCAN_LEFT:
792 case SCAN_RIGHT:
793 if (DateOrTime && !ManualInput) {
794 //
795 // By setting this value, we will return back to the caller.
796 // We need to do this since an auto-refresh will destroy the adjustment
797 // based on what the real-time-clock is showing. So we always commit
798 // upon changing the value.
799 //
800 gDirection = SCAN_DOWN;
801 }
802
803 if ((Step != 0) && !ManualInput) {
804 if (Key.ScanCode == SCAN_LEFT) {
805 if (IntInput) {
806 if ((INT64)EditValue >= (INT64)Minimum + (INT64)Step) {
807 EditValue = EditValue - Step;
808 } else if ((INT64)EditValue > (INT64)Minimum) {
809 EditValue = Minimum;
810 } else {
811 EditValue = Maximum;
812 }
813 } else {
814 if (EditValue >= Minimum + Step) {
815 EditValue = EditValue - Step;
816 } else if (EditValue > Minimum) {
817 EditValue = Minimum;
818 } else {
819 EditValue = Maximum;
820 }
821 }
822 } else if (Key.ScanCode == SCAN_RIGHT) {
823 if (IntInput) {
824 if ((INT64)EditValue + (INT64)Step <= (INT64)Maximum) {
825 EditValue = EditValue + Step;
826 } else if ((INT64)EditValue < (INT64)Maximum) {
827 EditValue = Maximum;
828 } else {
829 EditValue = Minimum;
830 }
831 } else {
832 if (EditValue + Step <= Maximum) {
833 EditValue = EditValue + Step;
834 } else if (EditValue < Maximum) {
835 EditValue = Maximum;
836 } else {
837 EditValue = Minimum;
838 }
839 }
840 }
841
842 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
843 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
844 if (MenuOption->Sequence == 2) {
845 //
846 // Year
847 //
848 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16)EditValue);
849 } else {
850 //
851 // Month/Day
852 //
853 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
854 }
855
856 if (MenuOption->Sequence == 0) {
857 ASSERT (EraseLen >= 2);
858 FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;
859 } else if (MenuOption->Sequence == 1) {
860 ASSERT (EraseLen >= 1);
861 FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;
862 }
863 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
864 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8)EditValue);
865
866 if (MenuOption->Sequence == 0) {
867 ASSERT (EraseLen >= 2);
868 FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;
869 } else if (MenuOption->Sequence == 1) {
870 ASSERT (EraseLen >= 1);
871 FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;
872 }
873 } else {
874 QuestionValue->Value.u64 = EditValue;
875 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
876 }
877
878 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
879 for (Loop = 0; Loop < EraseLen; Loop++) {
880 PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
881 }
882
883 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
884
885 if (MenuOption->Sequence == 0) {
886 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
887 Column = MenuOption->OptCol + 1;
888 }
889
890 PrintStringAt (Column, Row, FormattedNumber);
891
892 if (!DateOrTime || (MenuOption->Sequence == 2)) {
893 PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
894 }
895 }
896
897 goto EnterCarriageReturn;
898
899 case SCAN_UP:
900 case SCAN_DOWN:
901 goto EnterCarriageReturn;
902
903 case SCAN_ESC:
904 return EFI_DEVICE_ERROR;
905
906 default:
907 break;
908 }
909
910 break;
911
912EnterCarriageReturn:
913
914 case CHAR_CARRIAGE_RETURN:
915 //
916 // Validate input value with Minimum value.
917 //
918 ValidateFail = FALSE;
919 if (IntInput) {
920 //
921 // After user input Enter, need to check whether the input value.
922 // If input a negative value, should compare with maximum value.
923 // else compare with the minimum value.
924 //
925 if (Negative) {
926 ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
927 } else {
928 ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
929 }
930
931 if (ValidateFail) {
932 UpdateStatusBar (INPUT_ERROR, TRUE);
933 break;
934 }
935 } else if (EditValue < Minimum) {
936 UpdateStatusBar (INPUT_ERROR, TRUE);
937 break;
938 }
939
940 UpdateStatusBar (INPUT_ERROR, FALSE);
941 CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
942 QuestionValue = &gUserInput->InputValue;
943 //
944 // Store Edit value back to Question
945 //
946 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
947 switch (MenuOption->Sequence) {
948 case 0:
949 QuestionValue->Value.date.Month = (UINT8)EditValue;
950 break;
951
952 case 1:
953 QuestionValue->Value.date.Day = (UINT8)EditValue;
954 break;
955
956 case 2:
957 QuestionValue->Value.date.Year = (UINT16)EditValue;
958 break;
959
960 default:
961 break;
962 }
963 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
964 switch (MenuOption->Sequence) {
965 case 0:
966 QuestionValue->Value.time.Hour = (UINT8)EditValue;
967 break;
968
969 case 1:
970 QuestionValue->Value.time.Minute = (UINT8)EditValue;
971 break;
972
973 case 2:
974 QuestionValue->Value.time.Second = (UINT8)EditValue;
975 break;
976
977 default:
978 break;
979 }
980 } else {
981 //
982 // Numeric
983 //
984 QuestionValue->Value.u64 = EditValue;
985 }
986
987 //
988 // Adjust the value to the correct one.
989 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01
990 // 2013.03.29 -> 2013.02.29 -> 2013.02.28
991 //
992 if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) &&
993 ((MenuOption->Sequence == 0) || (MenuOption->Sequence == 2)))
994 {
995 AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
996 }
997
998 return EFI_SUCCESS;
999
1000 case CHAR_BACKSPACE:
1001 if (ManualInput) {
1002 if (Count == 0) {
1003 if (Negative) {
1004 Negative = FALSE;
1005 Column--;
1006 PrintStringAt (Column, Row, L" ");
1007 }
1008
1009 break;
1010 }
1011
1012 //
1013 // Remove a character
1014 //
1015 EditValue = PreviousNumber[Count - 1];
1016 UpdateStatusBar (INPUT_ERROR, FALSE);
1017 Count--;
1018 Column--;
1019 PrintStringAt (Column, Row, L" ");
1020 }
1021
1022 break;
1023
1024 default:
1025 if (ManualInput) {
1026 if (HexInput) {
1027 if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {
1028 Digital = (UINT8)(Key.UnicodeChar - L'0');
1029 } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {
1030 Digital = (UINT8)(Key.UnicodeChar - L'A' + 0x0A);
1031 } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {
1032 Digital = (UINT8)(Key.UnicodeChar - L'a' + 0x0A);
1033 } else {
1034 UpdateStatusBar (INPUT_ERROR, TRUE);
1035 break;
1036 }
1037 } else {
1038 if ((Key.UnicodeChar > L'9') || (Key.UnicodeChar < L'0')) {
1039 UpdateStatusBar (INPUT_ERROR, TRUE);
1040 break;
1041 }
1042 }
1043
1044 //
1045 // If Count exceed input width, there is no way more is valid
1046 //
1047 if (Count >= InputWidth) {
1048 break;
1049 }
1050
1051 //
1052 // Someone typed something valid!
1053 //
1054 if (Count != 0) {
1055 if (HexInput) {
1056 EditValue = LShiftU64 (EditValue, 4) + Digital;
1057 } else if (IntInput && Negative) {
1058 //
1059 // Save the negative number.
1060 //
1061 EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;
1062 } else {
1063 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
1064 }
1065 } else {
1066 if (HexInput) {
1067 EditValue = Digital;
1068 } else if (IntInput && Negative) {
1069 //
1070 // Save the negative number.
1071 //
1072 EditValue = ~(Key.UnicodeChar - L'0') + 1;
1073 } else {
1074 EditValue = Key.UnicodeChar - L'0';
1075 }
1076 }
1077
1078 if (IntInput) {
1079 ValidateFail = FALSE;
1080 //
1081 // When user input a new value, should check the current value.
1082 // If user input a negative value, should compare it with minimum
1083 // value, else compare it with maximum value.
1084 //
1085 if (Negative) {
1086 ValidateFail = (INT64)EditValue < (INT64)Minimum ? TRUE : FALSE;
1087 } else {
1088 ValidateFail = (INT64)EditValue > (INT64)Maximum ? TRUE : FALSE;
1089 }
1090
1091 if (ValidateFail) {
1092 UpdateStatusBar (INPUT_ERROR, TRUE);
1093 ASSERT (Count < ARRAY_SIZE (PreviousNumber));
1094 EditValue = PreviousNumber[Count];
1095 break;
1096 }
1097 } else {
1098 if (EditValue > Maximum) {
1099 UpdateStatusBar (INPUT_ERROR, TRUE);
1100 ASSERT (Count < ARRAY_SIZE (PreviousNumber));
1101 EditValue = PreviousNumber[Count];
1102 break;
1103 }
1104 }
1105
1106 UpdateStatusBar (INPUT_ERROR, FALSE);
1107
1108 Count++;
1109 ASSERT (Count < (ARRAY_SIZE (PreviousNumber)));
1110 PreviousNumber[Count] = EditValue;
1111
1112 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
1113 PrintCharAt (Column, Row, Key.UnicodeChar);
1114 Column++;
1115 }
1116
1117 break;
1118 }
1119 } while (TRUE);
1120}
1121
1135 OUT UINTN *PopUpMenuLines
1136 )
1137{
1138 UINTN Index;
1139 EFI_IFR_ORDERED_LIST *OrderList;
1140 UINT8 *ValueArray;
1141 UINT8 ValueType;
1142 LIST_ENTRY *Link;
1143 DISPLAY_QUESTION_OPTION *OneOfOption;
1144 EFI_HII_VALUE *HiiValueArray;
1145
1146 Link = GetFirstNode (&Question->OptionListHead);
1147 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1148 ValueArray = Question->CurrentValue.Buffer;
1149 ValueType = OneOfOption->OptionOpCode->Type;
1150 OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
1151
1152 for (Index = 0; Index < OrderList->MaxContainers; Index++) {
1153 if (GetArrayData (ValueArray, ValueType, Index) == 0) {
1154 break;
1155 }
1156 }
1157
1158 *PopUpMenuLines = Index;
1159
1160 //
1161 // Prepare HiiValue array
1162 //
1163 HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));
1164 ASSERT (HiiValueArray != NULL);
1165
1166 for (Index = 0; Index < *PopUpMenuLines; Index++) {
1167 HiiValueArray[Index].Type = ValueType;
1168 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1169 }
1170
1171 for (Index = 0; Index < *PopUpMenuLines; Index++) {
1172 OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);
1173 if (OneOfOption == NULL) {
1174 return EFI_NOT_FOUND;
1175 }
1176
1177 RemoveEntryList (&OneOfOption->Link);
1178
1179 //
1180 // Insert to head.
1181 //
1182 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
1183 }
1184
1185 FreePool (HiiValueArray);
1186
1187 return EFI_SUCCESS;
1188}
1189
1201BOOLEAN
1203 IN EFI_IFR_TYPE_VALUE *Value1,
1204 IN EFI_IFR_TYPE_VALUE *Value2,
1205 IN UINT8 Type
1206 )
1207{
1208 switch (Type) {
1209 case EFI_IFR_TYPE_BOOLEAN:
1210 case EFI_IFR_TYPE_NUM_SIZE_8:
1211 return (BOOLEAN)(Value1->u8 == Value2->u8);
1212
1213 case EFI_IFR_TYPE_NUM_SIZE_16:
1214 return (BOOLEAN)(Value1->u16 == Value2->u16);
1215
1216 case EFI_IFR_TYPE_NUM_SIZE_32:
1217 return (BOOLEAN)(Value1->u32 == Value2->u32);
1218
1219 case EFI_IFR_TYPE_NUM_SIZE_64:
1220 return (BOOLEAN)(Value1->u64 == Value2->u64);
1221
1222 default:
1223 ASSERT (FALSE);
1224 return FALSE;
1225 }
1226}
1227
1236VOID
1238 OUT EFI_IFR_TYPE_VALUE *Dest,
1239 IN EFI_IFR_TYPE_VALUE *Source,
1240 IN UINT8 Type
1241 )
1242{
1243 switch (Type) {
1244 case EFI_IFR_TYPE_BOOLEAN:
1245 Dest->b = Source->b;
1246 break;
1247
1248 case EFI_IFR_TYPE_NUM_SIZE_8:
1249 Dest->u8 = Source->u8;
1250 break;
1251
1252 case EFI_IFR_TYPE_NUM_SIZE_16:
1253 Dest->u16 = Source->u16;
1254 break;
1255
1256 case EFI_IFR_TYPE_NUM_SIZE_32:
1257 Dest->u32 = Source->u32;
1258 break;
1259
1260 case EFI_IFR_TYPE_NUM_SIZE_64:
1261 Dest->u64 = Source->u64;
1262 break;
1263
1264 default:
1265 ASSERT (FALSE);
1266 break;
1267 }
1268}
1269
1281 IN UI_MENU_OPTION *MenuOption
1282 )
1283{
1284 EFI_INPUT_KEY Key;
1285 UINTN Index;
1286 CHAR16 *StringPtr;
1287 CHAR16 *TempStringPtr;
1288 UINTN Index2;
1289 UINTN TopOptionIndex;
1290 UINTN HighlightOptionIndex;
1291 UINTN Start;
1292 UINTN End;
1293 UINTN Top;
1294 UINTN Bottom;
1295 UINTN PopUpMenuLines;
1296 UINTN MenuLinesInView;
1297 UINTN PopUpWidth;
1298 CHAR16 Character;
1299 INT32 SavedAttribute;
1300 BOOLEAN ShowDownArrow;
1301 BOOLEAN ShowUpArrow;
1302 UINTN DimensionsWidth;
1303 LIST_ENTRY *Link;
1304 BOOLEAN OrderedList;
1305 UINT8 *ValueArray;
1306 UINT8 *ReturnValue;
1307 UINT8 ValueType;
1308 EFI_HII_VALUE HiiValue;
1309 DISPLAY_QUESTION_OPTION *OneOfOption;
1310 DISPLAY_QUESTION_OPTION *CurrentOption;
1312 INTN Result;
1313 EFI_IFR_ORDERED_LIST *OrderList;
1314
1315 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
1316
1317 ValueArray = NULL;
1318 ValueType = 0;
1319 CurrentOption = NULL;
1320 ShowDownArrow = FALSE;
1321 ShowUpArrow = FALSE;
1322
1323 ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));
1324
1325 Question = MenuOption->ThisTag;
1326 if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1327 Link = GetFirstNode (&Question->OptionListHead);
1328 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1329 ValueArray = Question->CurrentValue.Buffer;
1330 ValueType = OneOfOption->OptionOpCode->Type;
1331 OrderedList = TRUE;
1332 OrderList = (EFI_IFR_ORDERED_LIST *)Question->OpCode;
1333 } else {
1334 OrderedList = FALSE;
1335 OrderList = NULL;
1336 }
1337
1338 //
1339 // Calculate Option count
1340 //
1341 PopUpMenuLines = 0;
1342 if (OrderedList) {
1343 AdjustOptionOrder (Question, &PopUpMenuLines);
1344 } else {
1345 Link = GetFirstNode (&Question->OptionListHead);
1346 while (!IsNull (&Question->OptionListHead, Link)) {
1347 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1348 PopUpMenuLines++;
1349 Link = GetNextNode (&Question->OptionListHead, Link);
1350 }
1351 }
1352
1353 //
1354 // Get the number of one of options present and its size
1355 //
1356 PopUpWidth = 0;
1357 HighlightOptionIndex = 0;
1358 Link = GetFirstNode (&Question->OptionListHead);
1359 for (Index = 0; Index < PopUpMenuLines; Index++) {
1360 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1361
1362 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1363 if (StrLen (StringPtr) > PopUpWidth) {
1364 PopUpWidth = StrLen (StringPtr);
1365 }
1366
1367 FreePool (StringPtr);
1368 HiiValue.Type = OneOfOption->OptionOpCode->Type;
1369 SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);
1370 if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {
1371 //
1372 // Find current selected Option for OneOf
1373 //
1374 HighlightOptionIndex = Index;
1375 }
1376
1377 Link = GetNextNode (&Question->OptionListHead, Link);
1378 }
1379
1380 //
1381 // Perform popup menu initialization.
1382 //
1383 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
1384
1385 SavedAttribute = gST->ConOut->Mode->Attribute;
1386 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1387
1388 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
1389 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
1390 }
1391
1392 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;
1393 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;
1394 Top = gStatementDimensions.TopRow;
1395 Bottom = gStatementDimensions.BottomRow - 1;
1396
1397 MenuLinesInView = Bottom - Top - 1;
1398 if (MenuLinesInView >= PopUpMenuLines) {
1399 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
1400 Bottom = Top + PopUpMenuLines + 1;
1401 } else {
1402 ShowDownArrow = TRUE;
1403 }
1404
1405 if (HighlightOptionIndex > (MenuLinesInView - 1)) {
1406 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
1407 } else {
1408 TopOptionIndex = 0;
1409 }
1410
1411 do {
1412 //
1413 // Clear that portion of the screen
1414 //
1415 ClearLines (Start, End, Top, Bottom, GetPopupColor ());
1416
1417 //
1418 // Draw "One of" pop-up menu
1419 //
1420 Character = BOXDRAW_DOWN_RIGHT;
1421 PrintCharAt (Start, Top, Character);
1422 for (Index = Start; Index + 2 < End; Index++) {
1423 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {
1424 Character = GEOMETRICSHAPE_UP_TRIANGLE;
1425 } else {
1426 Character = BOXDRAW_HORIZONTAL;
1427 }
1428
1429 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1430 }
1431
1432 Character = BOXDRAW_DOWN_LEFT;
1433 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1434 Character = BOXDRAW_VERTICAL;
1435 for (Index = Top + 1; Index < Bottom; Index++) {
1436 PrintCharAt (Start, Index, Character);
1437 PrintCharAt (End - 1, Index, Character);
1438 }
1439
1440 //
1441 // Move to top Option
1442 //
1443 Link = GetFirstNode (&Question->OptionListHead);
1444 for (Index = 0; Index < TopOptionIndex; Index++) {
1445 Link = GetNextNode (&Question->OptionListHead, Link);
1446 }
1447
1448 //
1449 // Display the One of options
1450 //
1451 Index2 = Top + 1;
1452 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
1453 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1454 Link = GetNextNode (&Question->OptionListHead, Link);
1455
1456 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1457 ASSERT (StringPtr != NULL);
1458 //
1459 // If the string occupies multiple lines, truncate it to fit in one line,
1460 // and append a "..." for indication.
1461 //
1462 if (StrLen (StringPtr) > (PopUpWidth - 1)) {
1463 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));
1464 ASSERT (TempStringPtr != NULL);
1465 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));
1466 FreePool (StringPtr);
1467 StringPtr = TempStringPtr;
1468 StrCatS (StringPtr, PopUpWidth - 1, L"...");
1469 }
1470
1471 if (Index == HighlightOptionIndex) {
1472 //
1473 // Highlight the selected one
1474 //
1475 CurrentOption = OneOfOption;
1476
1477 gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
1478 PrintStringAt (Start + 2, Index2, StringPtr);
1479 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1480 } else {
1481 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1482 PrintStringAt (Start + 2, Index2, StringPtr);
1483 }
1484
1485 Index2++;
1486 FreePool (StringPtr);
1487 }
1488
1489 Character = BOXDRAW_UP_RIGHT;
1490 PrintCharAt (Start, Bottom, Character);
1491 for (Index = Start; Index + 2 < End; Index++) {
1492 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {
1493 Character = GEOMETRICSHAPE_DOWN_TRIANGLE;
1494 } else {
1495 Character = BOXDRAW_HORIZONTAL;
1496 }
1497
1498 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1499 }
1500
1501 Character = BOXDRAW_UP_LEFT;
1502 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1503
1504 //
1505 // Get User selection
1506 //
1507 Key.UnicodeChar = CHAR_NULL;
1508 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
1509 Key.ScanCode = gDirection;
1510 gDirection = 0;
1511 goto TheKey;
1512 }
1513
1514 WaitForKeyStroke (&Key);
1515
1516TheKey:
1517 switch (Key.UnicodeChar) {
1518 case '+':
1519 if (OrderedList) {
1520 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1521 //
1522 // Highlight reaches the top of the popup window, scroll one menu item.
1523 //
1524 TopOptionIndex--;
1525 ShowDownArrow = TRUE;
1526 }
1527
1528 if (TopOptionIndex == 0) {
1529 ShowUpArrow = FALSE;
1530 }
1531
1532 if (HighlightOptionIndex > 0) {
1533 HighlightOptionIndex--;
1534
1535 ASSERT (CurrentOption != NULL);
1536 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
1537 }
1538 }
1539
1540 break;
1541
1542 case '-':
1543 //
1544 // If an ordered list op-code, we will allow for a popup of +/- keys
1545 // to create an ordered list of items
1546 //
1547 if (OrderedList) {
1548 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1549 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
1550 {
1551 //
1552 // Highlight reaches the bottom of the popup window, scroll one menu item.
1553 //
1554 TopOptionIndex++;
1555 ShowUpArrow = TRUE;
1556 }
1557
1558 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1559 ShowDownArrow = FALSE;
1560 }
1561
1562 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1563 HighlightOptionIndex++;
1564
1565 ASSERT (CurrentOption != NULL);
1566 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
1567 }
1568 }
1569
1570 break;
1571
1572 case '^':
1573 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1574 //
1575 // Highlight reaches the top of the popup window, scroll one menu item.
1576 //
1577 TopOptionIndex--;
1578 ShowDownArrow = TRUE;
1579 }
1580
1581 if (TopOptionIndex == 0) {
1582 ShowUpArrow = FALSE;
1583 }
1584
1585 if (HighlightOptionIndex > 0) {
1586 HighlightOptionIndex--;
1587 }
1588
1589 break;
1590
1591 case 'V':
1592 case 'v':
1593 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1594 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
1595 {
1596 //
1597 // Highlight reaches the bottom of the popup window, scroll one menu item.
1598 //
1599 TopOptionIndex++;
1600 ShowUpArrow = TRUE;
1601 }
1602
1603 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1604 ShowDownArrow = FALSE;
1605 }
1606
1607 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1608 HighlightOptionIndex++;
1609 }
1610
1611 break;
1612
1613 case CHAR_NULL:
1614 switch (Key.ScanCode) {
1615 case SCAN_UP:
1616 case SCAN_DOWN:
1617 if (Key.ScanCode == SCAN_UP) {
1618 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1619 //
1620 // Highlight reaches the top of the popup window, scroll one menu item.
1621 //
1622 TopOptionIndex--;
1623 ShowDownArrow = TRUE;
1624 }
1625
1626 if (TopOptionIndex == 0) {
1627 ShowUpArrow = FALSE;
1628 }
1629
1630 if (HighlightOptionIndex > 0) {
1631 HighlightOptionIndex--;
1632 }
1633 } else {
1634 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1635 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1)))
1636 {
1637 //
1638 // Highlight reaches the bottom of the popup window, scroll one menu item.
1639 //
1640 TopOptionIndex++;
1641 ShowUpArrow = TRUE;
1642 }
1643
1644 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1645 ShowDownArrow = FALSE;
1646 }
1647
1648 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1649 HighlightOptionIndex++;
1650 }
1651 }
1652
1653 break;
1654
1655 case SCAN_ESC:
1656 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1657
1658 //
1659 // Restore link list order for orderedlist
1660 //
1661 if (OrderedList) {
1662 HiiValue.Type = ValueType;
1663 HiiValue.Value.u64 = 0;
1664 for (Index = 0; Index < OrderList->MaxContainers; Index++) {
1665 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1666 if (HiiValue.Value.u64 == 0) {
1667 break;
1668 }
1669
1670 OneOfOption = ValueToOption (Question, &HiiValue);
1671 if (OneOfOption == NULL) {
1672 return EFI_NOT_FOUND;
1673 }
1674
1675 RemoveEntryList (&OneOfOption->Link);
1676 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
1677 }
1678 }
1679
1680 return EFI_DEVICE_ERROR;
1681
1682 default:
1683 break;
1684 }
1685
1686 break;
1687
1688 case CHAR_CARRIAGE_RETURN:
1689 //
1690 // return the current selection
1691 //
1692 if (OrderedList) {
1693 ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
1694 ASSERT (ReturnValue != NULL);
1695 Index = 0;
1696 Link = GetFirstNode (&Question->OptionListHead);
1697 while (!IsNull (&Question->OptionListHead, Link)) {
1698 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1699 Link = GetNextNode (&Question->OptionListHead, Link);
1700
1701 SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);
1702
1703 Index++;
1704 if (Index > OrderList->MaxContainers) {
1705 break;
1706 }
1707 }
1708
1709 if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
1710 FreePool (ReturnValue);
1711 return EFI_DEVICE_ERROR;
1712 } else {
1713 gUserInput->InputValue.Buffer = ReturnValue;
1714 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1715 }
1716 } else {
1717 ASSERT (CurrentOption != NULL);
1718 gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;
1719 if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {
1720 return EFI_DEVICE_ERROR;
1721 } else {
1722 SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
1723 }
1724 }
1725
1726 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1727
1728 return EFI_SUCCESS;
1729
1730 default:
1731 break;
1732 }
1733 } while (TRUE);
1734}
UINT64 UINTN
INT64 INTN
BOOLEAN EFIAPI IsNull(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:443
RETURN_STATUS EFIAPI StrCpyS(OUT CHAR16 *Destination, IN UINTN DestMax, IN CONST CHAR16 *Source)
Definition: SafeString.c:226
LIST_ENTRY *EFIAPI GetNextNode(IN CONST LIST_ENTRY *List, IN CONST LIST_ENTRY *Node)
Definition: LinkedList.c:333
LIST_ENTRY *EFIAPI InsertHeadList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:218
LIST_ENTRY *EFIAPI GetFirstNode(IN CONST LIST_ENTRY *List)
Definition: LinkedList.c:298
LIST_ENTRY *EFIAPI SwapListEntries(IN OUT LIST_ENTRY *FirstEntry, IN OUT LIST_ENTRY *SecondEntry)
Definition: LinkedList.c:522
RETURN_STATUS EFIAPI StrCatS(IN OUT CHAR16 *Destination, IN UINTN DestMax, IN CONST CHAR16 *Source)
Definition: SafeString.c:405
LIST_ENTRY *EFIAPI RemoveEntryList(IN CONST LIST_ENTRY *Entry)
Definition: LinkedList.c:590
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition: MultU64x32.c:27
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
RETURN_STATUS EFIAPI StrnCpyS(OUT CHAR16 *Destination, IN UINTN DestMax, IN CONST CHAR16 *Source, IN UINTN Length)
Definition: SafeString.c:310
UINTN EFIAPI StrLen(IN CONST CHAR16 *String)
Definition: String.c:30
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINTN PrintCharAt(IN UINTN Column, IN UINTN Row, CHAR16 Character)
UINTN PrintStringAt(IN UINTN Column, IN UINTN Row, IN CHAR16 *String)
VOID EFIAPI CreateDialog(OUT EFI_INPUT_KEY *Key OPTIONAL,...)
UINT8 EFIAPI GetPopupColor(VOID)
VOID EFIAPI UpdateStatusBar(IN UINTN MessageType, IN BOOLEAN State)
UINT8 EFIAPI GetFieldTextColor(VOID)
VOID EFIAPI ClearLines(IN UINTN LeftColumn, IN UINTN RightColumn, IN UINTN TopRow, IN UINTN BottomRow, IN UINTN TextAttribute)
UINT8 EFIAPI GetHighlightTextColor(VOID)
UINT8 EFIAPI GetPickListColor(VOID)
EFI_STATUS WaitForKeyStroke(OUT EFI_INPUT_KEY *Key)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
CHAR16 * GetToken(IN EFI_STRING_ID Token, IN EFI_HII_HANDLE HiiHandle)
Definition: FormDisplay.c:191
UINTN GetStringWidth(IN CHAR16 *String)
Definition: FormDisplay.c:830
VOID SetUnicodeMem(IN VOID *Buffer, IN UINTN Size, IN CHAR16 Value)
Definition: FormDisplay.c:4210
EFI_STATUS CompareHiiValue(IN EFI_HII_VALUE *Value1, IN EFI_HII_VALUE *Value2, OUT INTN *Result, IN EFI_HII_HANDLE HiiHandle OPTIONAL)
VOID EFIAPI CreateMultiStringPopUp(IN UINTN RequestedWidth, IN UINTN NumberOfLines,...)
EFI_STATUS PrintFormattedNumber(IN FORM_DISPLAY_ENGINE_STATEMENT *Question, IN OUT CHAR16 *FormattedNumber, IN UINTN BufferSize)
UINT64 GetArrayData(IN VOID *Array, IN UINT8 Type, IN UINTN Index)
VOID SetArrayData(IN VOID *Array, IN UINT8 Type, IN UINTN Index, IN UINT64 Value)
DISPLAY_QUESTION_OPTION * ValueToOption(IN FORM_DISPLAY_ENGINE_STATEMENT *Question, IN EFI_HII_VALUE *OptionValue)
EFI_STATUS GetNumericInput(IN UI_MENU_OPTION *MenuOption)
Definition: InputHandler.c:487
EFI_STATUS ReadString(IN UI_MENU_OPTION *MenuOption, IN CHAR16 *Prompt, IN OUT CHAR16 *StringPtr)
Definition: InputHandler.c:56
VOID GetValueFromNum(IN EFI_IFR_OP_HEADER *OpCode, IN BOOLEAN IntInput, IN EFI_HII_VALUE *QuestionValue, OUT UINT64 *Value, OUT UINT64 *Minimum, OUT UINT64 *Maximum, OUT UINT64 *Step, OUT UINT16 *StorageWidth)
Definition: InputHandler.c:392
BOOLEAN IsValuesEqual(IN EFI_IFR_TYPE_VALUE *Value1, IN EFI_IFR_TYPE_VALUE *Value2, IN UINT8 Type)
EFI_STATUS GetSelectionInputPopUp(IN UI_MENU_OPTION *MenuOption)
VOID AdjustQuestionValue(IN EFI_HII_VALUE *QuestionValue, IN UINT8 Sequence)
Definition: InputHandler.c:325
VOID SetValuesByType(OUT EFI_IFR_TYPE_VALUE *Dest, IN EFI_IFR_TYPE_VALUE *Source, IN UINT8 Type)
EFI_STATUS AdjustOptionOrder(IN FORM_DISPLAY_ENGINE_STATEMENT *Question, OUT UINTN *PopUpMenuLines)
VOID GetFieldFromOp(IN EFI_IFR_OP_HEADER *OpCode, OUT UINTN *Minimum, OUT UINTN *Maximum)
Definition: InputHandler.c:21
UINTN EFIAPI UnicodeSPrint(OUT CHAR16 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR16 *FormatString,...)
Definition: PrintLib.c:408
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define ARRAY_SIZE(Array)
Definition: Base.h:1393
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_SYSTEM_TABLE * gST
EFI_SIMPLE_TEXT_OUTPUT_MODE * Mode
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL * ConOut
Definition: UefiSpec.h:2064