VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c@ 75265

Last change on this file since 75265 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

  • Property svn:eol-style set to native
File size: 43.1 KB
Line 
1/** @file
2Implementation for handling user input from the User Interfaces.
3
4Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "FormDisplay.h"
16
17/**
18 Get maximum and minimum info from this opcode.
19
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.
23
24**/
25VOID
26GetFieldFromOp (
27 IN EFI_IFR_OP_HEADER *OpCode,
28 OUT UINTN *Minimum,
29 OUT UINTN *Maximum
30 )
31{
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;
42 } else {
43 *Minimum = 0;
44 *Maximum = 0;
45 }
46}
47
48/**
49 Get string or password input from user.
50
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.
54
55 @retval EFI_SUCCESS If string input is read successfully
56 @retval EFI_DEVICE_ERROR If operation fails
57
58**/
59EFI_STATUS
60ReadString (
61 IN UI_MENU_OPTION *MenuOption,
62 IN CHAR16 *Prompt,
63 IN OUT CHAR16 *StringPtr
64 )
65{
66 EFI_STATUS Status;
67 EFI_INPUT_KEY Key;
68 CHAR16 NullCharacter;
69 UINTN ScreenSize;
70 CHAR16 Space[2];
71 CHAR16 KeyPad[2];
72 CHAR16 *TempString;
73 CHAR16 *BufferedString;
74 UINTN Index;
75 UINTN Index2;
76 UINTN Count;
77 UINTN Start;
78 UINTN Top;
79 UINTN DimensionsWidth;
80 UINTN DimensionsHeight;
81 UINTN CurrentCursor;
82 BOOLEAN CursorVisible;
83 UINTN Minimum;
84 UINTN Maximum;
85 FORM_DISPLAY_ENGINE_STATEMENT *Question;
86 BOOLEAN IsPassword;
87
88 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
89 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;
90
91 NullCharacter = CHAR_NULL;
92 ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);
93 Space[0] = L' ';
94 Space[1] = CHAR_NULL;
95
96 Question = MenuOption->ThisTag;
97 GetFieldFromOp(Question->OpCode, &Minimum, &Maximum);
98
99 if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {
100 IsPassword = TRUE;
101 } else {
102 IsPassword = FALSE;
103 }
104
105 TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));
106 ASSERT (TempString);
107
108 if (ScreenSize < (Maximum + 1)) {
109 ScreenSize = Maximum + 1;
110 }
111
112 if ((ScreenSize + 2) > DimensionsWidth) {
113 ScreenSize = DimensionsWidth - 2;
114 }
115
116 BufferedString = AllocateZeroPool (ScreenSize * 2);
117 ASSERT (BufferedString);
118
119 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;
120 Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;
121
122 //
123 // Display prompt for string
124 //
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));
128
129 CursorVisible = gST->ConOut->Mode->CursorVisible;
130 gST->ConOut->EnableCursor (gST->ConOut, TRUE);
131
132 CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;
133 if (CurrentCursor != 0) {
134 //
135 // Show the string which has beed saved before.
136 //
137 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
138 PrintStringAt (Start + 1, Top + 3, BufferedString);
139
140 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
141 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
142 } else {
143 Index = 0;
144 }
145
146 if (IsPassword) {
147 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
148 }
149
150 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
151 BufferedString[Count] = StringPtr[Index];
152
153 if (IsPassword) {
154 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
155 }
156 }
157
158 if (!IsPassword) {
159 PrintStringAt (Start + 1, Top + 3, BufferedString);
160 }
161
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);
164 }
165
166 do {
167 Status = WaitForKeyStroke (&Key);
168 ASSERT_EFI_ERROR (Status);
169
170 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
171 switch (Key.UnicodeChar) {
172 case CHAR_NULL:
173 switch (Key.ScanCode) {
174 case SCAN_LEFT:
175 if (CurrentCursor > 0) {
176 CurrentCursor--;
177 }
178 break;
179
180 case SCAN_RIGHT:
181 if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {
182 CurrentCursor++;
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 default:
194 break;
195 }
196
197 break;
198
199 case CHAR_CARRIAGE_RETURN:
200 if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {
201
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);
206 return EFI_SUCCESS;
207 } else {
208 //
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.
211 //
212 do {
213 CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);
214 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
215
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;
221 }
222
223 break;
224
225 case CHAR_BACKSPACE:
226 if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {
227 for (Index = 0; Index < CurrentCursor - 1; Index++) {
228 TempString[Index] = StringPtr[Index];
229 }
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];
234 }
235 TempString[Index] = CHAR_NULL;
236 }
237 //
238 // Effectively truncate string by 1 character
239 //
240 StrCpy (StringPtr, TempString);
241 CurrentCursor --;
242 }
243
244 default:
245 //
246 // If it is the beginning of the string, don't worry about checking maximum limits
247 //
248 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {
249 StrnCpy (StringPtr, &Key.UnicodeChar, 1);
250 CurrentCursor++;
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];
258 }
259 TempString[Index] = CHAR_NULL;
260 StrCat (TempString, KeyPad);
261 StrCat (TempString, StringPtr + CurrentCursor);
262 StrCpy (StringPtr, TempString);
263 } else {
264 StrCat (StringPtr, KeyPad);
265 }
266 CurrentCursor++;
267 }
268
269 //
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
272 //
273 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');
274 PrintStringAt (Start + 1, Top + 3, BufferedString);
275
276 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {
277 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;
278 } else {
279 Index = 0;
280 }
281
282 if (IsPassword) {
283 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);
284 }
285
286 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {
287 BufferedString[Count] = StringPtr[Index];
288
289 if (IsPassword) {
290 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');
291 }
292 }
293
294 if (!IsPassword) {
295 PrintStringAt (Start + 1, Top + 3, BufferedString);
296 }
297 break;
298 }
299
300 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
301 gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);
302 } while (TRUE);
303
304}
305
306/**
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
310
311 @param QuestionValue Pointer to current question.
312 @param Sequence The sequence of the field in the question.
313**/
314VOID
315AdjustQuestionValue (
316 IN EFI_HII_VALUE *QuestionValue,
317 IN UINT8 Sequence
318 )
319{
320 UINT8 Month;
321 UINT16 Year;
322 UINT8 Maximum;
323 UINT8 Minimum;
324
325 Month = QuestionValue->Value.date.Month;
326 Year = QuestionValue->Value.date.Year;
327 Minimum = 1;
328
329 switch (Month) {
330 case 2:
331 if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {
332 Maximum = 29;
333 } else {
334 Maximum = 28;
335 }
336 break;
337 case 4:
338 case 6:
339 case 9:
340 case 11:
341 Maximum = 30;
342 break;
343 default:
344 Maximum = 31;
345 break;
346 }
347
348 //
349 // Change the month area.
350 //
351 if (Sequence == 0) {
352 if (QuestionValue->Value.date.Day > Maximum) {
353 QuestionValue->Value.date.Day = Maximum;
354 }
355 }
356
357 //
358 // Change the Year area.
359 //
360 if (Sequence == 2) {
361 if (QuestionValue->Value.date.Day > Maximum) {
362 QuestionValue->Value.date.Day = Minimum;
363 }
364 }
365}
366
367/**
368 Get field info from numeric opcode.
369
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.
375
376**/
377VOID
378GetValueFromNum (
379 IN EFI_IFR_OP_HEADER *OpCode,
380 OUT UINT64 *Minimum,
381 OUT UINT64 *Maximum,
382 OUT UINT64 *Step,
383 OUT UINT16 *StorageWidth
384)
385{
386 EFI_IFR_NUMERIC *NumericOp;
387
388 NumericOp = (EFI_IFR_NUMERIC *) OpCode;
389
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);
396 break;
397
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);
403 break;
404
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);
410 break;
411
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);
417 break;
418
419 default:
420 break;
421 }
422
423 if (*Maximum == 0) {
424 *Maximum = (UINT64) -1;
425 }
426}
427
428/**
429 This routine reads a numeric value from the user input.
430
431 @param MenuOption Pointer to the current input menu.
432
433 @retval EFI_SUCCESS If numerical input is read successfully
434 @retval EFI_DEVICE_ERROR If operation fails
435
436**/
437EFI_STATUS
438GetNumericInput (
439 IN UI_MENU_OPTION *MenuOption
440 )
441{
442 EFI_STATUS Status;
443 UINTN Column;
444 UINTN Row;
445 CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];
446 CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];
447 UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];
448 UINTN Count;
449 UINTN Loop;
450 BOOLEAN ManualInput;
451 BOOLEAN HexInput;
452 BOOLEAN DateOrTime;
453 UINTN InputWidth;
454 UINT64 EditValue;
455 UINT64 Step;
456 UINT64 Minimum;
457 UINT64 Maximum;
458 UINTN EraseLen;
459 UINT8 Digital;
460 EFI_INPUT_KEY Key;
461 EFI_HII_VALUE *QuestionValue;
462 FORM_DISPLAY_ENGINE_STATEMENT *Question;
463 EFI_IFR_NUMERIC *NumericOp;
464 UINT16 StorageWidth;
465
466 Column = MenuOption->OptCol;
467 Row = MenuOption->Row;
468 PreviousNumber[0] = 0;
469 Count = 0;
470 InputWidth = 0;
471 Digital = 0;
472 StorageWidth = 0;
473 Minimum = 0;
474 Maximum = 0;
475 NumericOp = NULL;
476
477 Question = MenuOption->ThisTag;
478 QuestionValue = &Question->CurrentValue;
479
480 //
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
483 //
484 ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);
485
486 if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {
487 DateOrTime = TRUE;
488 } else {
489 DateOrTime = FALSE;
490 }
491
492 //
493 // Prepare Value to be edit
494 //
495 EraseLen = 0;
496 EditValue = 0;
497 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
498 Step = 1;
499 Minimum = 1;
500
501 switch (MenuOption->Sequence) {
502 case 0:
503 Maximum = 12;
504 EraseLen = 4;
505 EditValue = QuestionValue->Value.date.Month;
506 break;
507
508 case 1:
509 switch (QuestionValue->Value.date.Month) {
510 case 2:
511 if ((QuestionValue->Value.date.Year % 4) == 0 &&
512 ((QuestionValue->Value.date.Year % 100) != 0 ||
513 (QuestionValue->Value.date.Year % 400) == 0)) {
514 Maximum = 29;
515 } else {
516 Maximum = 28;
517 }
518 break;
519 case 4:
520 case 6:
521 case 9:
522 case 11:
523 Maximum = 30;
524 break;
525 default:
526 Maximum = 31;
527 break;
528 }
529
530 EraseLen = 3;
531 EditValue = QuestionValue->Value.date.Day;
532 break;
533
534 case 2:
535 Maximum = 0xffff;
536 EraseLen = 5;
537 EditValue = QuestionValue->Value.date.Year;
538 break;
539
540 default:
541 break;
542 }
543 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
544 Step = 1;
545 Minimum = 0;
546
547 switch (MenuOption->Sequence) {
548 case 0:
549 Maximum = 23;
550 EraseLen = 4;
551 EditValue = QuestionValue->Value.time.Hour;
552 break;
553
554 case 1:
555 Maximum = 59;
556 EraseLen = 3;
557 EditValue = QuestionValue->Value.time.Minute;
558 break;
559
560 case 2:
561 Maximum = 59;
562 EraseLen = 3;
563 EditValue = QuestionValue->Value.time.Second;
564 break;
565
566 default:
567 break;
568 }
569 } else {
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;
575 }
576
577 if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL) &&
578 ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {
579 HexInput = TRUE;
580 } else {
581 HexInput = FALSE;
582 }
583
584 //
585 // Enter from "Enter" input, clear the old word showing.
586 //
587 if (ManualInput) {
588 if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {
589 if (HexInput) {
590 InputWidth = StorageWidth * 2;
591 } else {
592 switch (StorageWidth) {
593 case 1:
594 InputWidth = 3;
595 break;
596
597 case 2:
598 InputWidth = 5;
599 break;
600
601 case 4:
602 InputWidth = 10;
603 break;
604
605 case 8:
606 InputWidth = 20;
607 break;
608
609 default:
610 InputWidth = 0;
611 break;
612 }
613 }
614
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';
620
621 PrintStringAt (Column, Row, InputText);
622 Column++;
623 }
624
625 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
626 if (MenuOption->Sequence == 2) {
627 InputWidth = 4;
628 } else {
629 InputWidth = 2;
630 }
631
632 if (MenuOption->Sequence == 0) {
633 InputText[0] = LEFT_NUMERIC_DELIMITER;
634 SetUnicodeMem (InputText + 1, InputWidth, L' ');
635 } else {
636 SetUnicodeMem (InputText, InputWidth, L' ');
637 }
638
639 if (MenuOption->Sequence == 2) {
640 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
641 } else {
642 InputText[InputWidth + 1] = DATE_SEPARATOR;
643 }
644 InputText[InputWidth + 2] = L'\0';
645
646 PrintStringAt (Column, Row, InputText);
647 if (MenuOption->Sequence == 0) {
648 Column++;
649 }
650 }
651
652 if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
653 InputWidth = 2;
654
655 if (MenuOption->Sequence == 0) {
656 InputText[0] = LEFT_NUMERIC_DELIMITER;
657 SetUnicodeMem (InputText + 1, InputWidth, L' ');
658 } else {
659 SetUnicodeMem (InputText, InputWidth, L' ');
660 }
661
662 if (MenuOption->Sequence == 2) {
663 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;
664 } else {
665 InputText[InputWidth + 1] = TIME_SEPARATOR;
666 }
667 InputText[InputWidth + 2] = L'\0';
668
669 PrintStringAt (Column, Row, InputText);
670 if (MenuOption->Sequence == 0) {
671 Column++;
672 }
673 }
674 }
675
676 //
677 // First time we enter this handler, we need to check to see if
678 // we were passed an increment or decrement directive
679 //
680 do {
681 Key.UnicodeChar = CHAR_NULL;
682 if (gDirection != 0) {
683 Key.ScanCode = gDirection;
684 gDirection = 0;
685 goto TheKey2;
686 }
687
688 Status = WaitForKeyStroke (&Key);
689
690TheKey2:
691 switch (Key.UnicodeChar) {
692
693 case '+':
694 case '-':
695 if (Key.UnicodeChar == '+') {
696 Key.ScanCode = SCAN_RIGHT;
697 } else {
698 Key.ScanCode = SCAN_LEFT;
699 }
700 Key.UnicodeChar = CHAR_NULL;
701 goto TheKey2;
702
703 case CHAR_NULL:
704 switch (Key.ScanCode) {
705 case SCAN_LEFT:
706 case SCAN_RIGHT:
707 if (DateOrTime && !ManualInput) {
708 //
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.
713 //
714 gDirection = SCAN_DOWN;
715 }
716
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){
722 EditValue = Minimum;
723 } else {
724 EditValue = Maximum;
725 }
726 } else if (Key.ScanCode == SCAN_RIGHT) {
727 if (EditValue + Step <= Maximum) {
728 EditValue = EditValue + Step;
729 } else if (EditValue < Maximum) {
730 EditValue = Maximum;
731 } else {
732 EditValue = Minimum;
733 }
734 }
735
736 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));
737 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
738 if (MenuOption->Sequence == 2) {
739 //
740 // Year
741 //
742 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);
743 } else {
744 //
745 // Month/Day
746 //
747 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
748 }
749
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;
756 }
757 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
758 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);
759
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;
766 }
767 } else {
768 QuestionValue->Value.u64 = EditValue;
769 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));
770 }
771
772 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());
773 for (Loop = 0; Loop < EraseLen; Loop++) {
774 PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");
775 }
776 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
777
778 if (MenuOption->Sequence == 0) {
779 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);
780 Column = MenuOption->OptCol + 1;
781 }
782
783 PrintStringAt (Column, Row, FormattedNumber);
784
785 if (!DateOrTime || MenuOption->Sequence == 2) {
786 PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);
787 }
788 }
789
790 goto EnterCarriageReturn;
791 break;
792
793 case SCAN_UP:
794 case SCAN_DOWN:
795 goto EnterCarriageReturn;
796
797 case SCAN_ESC:
798 return EFI_DEVICE_ERROR;
799
800 default:
801 break;
802 }
803
804 break;
805
806EnterCarriageReturn:
807
808 case CHAR_CARRIAGE_RETURN:
809 //
810 // Validate input value with Minimum value.
811 //
812 if (EditValue < Minimum) {
813 UpdateStatusBar (INPUT_ERROR, TRUE);
814 break;
815 } else {
816 UpdateStatusBar (INPUT_ERROR, FALSE);
817 }
818
819 CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));
820 QuestionValue = &gUserInput->InputValue;
821 //
822 // Store Edit value back to Question
823 //
824 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {
825 switch (MenuOption->Sequence) {
826 case 0:
827 QuestionValue->Value.date.Month = (UINT8) EditValue;
828 break;
829
830 case 1:
831 QuestionValue->Value.date.Day = (UINT8) EditValue;
832 break;
833
834 case 2:
835 QuestionValue->Value.date.Year = (UINT16) EditValue;
836 break;
837
838 default:
839 break;
840 }
841 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {
842 switch (MenuOption->Sequence) {
843 case 0:
844 QuestionValue->Value.time.Hour = (UINT8) EditValue;
845 break;
846
847 case 1:
848 QuestionValue->Value.time.Minute = (UINT8) EditValue;
849 break;
850
851 case 2:
852 QuestionValue->Value.time.Second = (UINT8) EditValue;
853 break;
854
855 default:
856 break;
857 }
858 } else {
859 //
860 // Numeric
861 //
862 QuestionValue->Value.u64 = EditValue;
863 }
864
865 //
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
869 //
870 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP &&
871 (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {
872 AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);
873 }
874
875 return EFI_SUCCESS;
876 break;
877
878 case CHAR_BACKSPACE:
879 if (ManualInput) {
880 if (Count == 0) {
881 break;
882 }
883 //
884 // Remove a character
885 //
886 EditValue = PreviousNumber[Count - 1];
887 UpdateStatusBar (INPUT_ERROR, FALSE);
888 Count--;
889 Column--;
890 PrintStringAt (Column, Row, L" ");
891 }
892 break;
893
894 default:
895 if (ManualInput) {
896 if (HexInput) {
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);
903 } else {
904 UpdateStatusBar (INPUT_ERROR, TRUE);
905 break;
906 }
907 } else {
908 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {
909 UpdateStatusBar (INPUT_ERROR, TRUE);
910 break;
911 }
912 }
913
914 //
915 // If Count exceed input width, there is no way more is valid
916 //
917 if (Count >= InputWidth) {
918 break;
919 }
920 //
921 // Someone typed something valid!
922 //
923 if (Count != 0) {
924 if (HexInput) {
925 EditValue = LShiftU64 (EditValue, 4) + Digital;
926 } else {
927 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');
928 }
929 } else {
930 if (HexInput) {
931 EditValue = Digital;
932 } else {
933 EditValue = Key.UnicodeChar - L'0';
934 }
935 }
936
937 if (EditValue > Maximum) {
938 UpdateStatusBar (INPUT_ERROR, TRUE);
939 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));
940 EditValue = PreviousNumber[Count];
941 break;
942 } else {
943 UpdateStatusBar (INPUT_ERROR, FALSE);
944 }
945
946 Count++;
947 ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));
948 PreviousNumber[Count] = EditValue;
949
950 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());
951 PrintCharAt (Column, Row, Key.UnicodeChar);
952 Column++;
953 }
954 break;
955 }
956 } while (TRUE);
957}
958
959/**
960 Adjust option order base on the question value.
961
962 @param Question Pointer to current question.
963 @param PopUpMenuLines The line number of the pop up menu.
964
965 @retval EFI_SUCCESS If Option input is processed successfully
966 @retval EFI_DEVICE_ERROR If operation fails
967
968**/
969EFI_STATUS
970AdjustOptionOrder (
971 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,
972 OUT UINTN *PopUpMenuLines
973 )
974{
975 UINTN Index;
976 EFI_IFR_ORDERED_LIST *OrderList;
977 UINT8 *ValueArray;
978 UINT8 ValueType;
979 LIST_ENTRY *Link;
980 DISPLAY_QUESTION_OPTION *OneOfOption;
981 EFI_HII_VALUE *HiiValueArray;
982
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;
988
989 for (Index = 0; Index < OrderList->MaxContainers; Index++) {
990 if (GetArrayData (ValueArray, ValueType, Index) == 0) {
991 break;
992 }
993 }
994
995 *PopUpMenuLines = Index;
996
997 //
998 // Prepare HiiValue array
999 //
1000 HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));
1001 ASSERT (HiiValueArray != NULL);
1002
1003 for (Index = 0; Index < *PopUpMenuLines; Index++) {
1004 HiiValueArray[Index].Type = ValueType;
1005 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);
1006 }
1007
1008 for (Index = 0; Index < *PopUpMenuLines; Index++) {
1009 OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);
1010 if (OneOfOption == NULL) {
1011 return EFI_NOT_FOUND;
1012 }
1013
1014 RemoveEntryList (&OneOfOption->Link);
1015
1016 //
1017 // Insert to head.
1018 //
1019 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);
1020 }
1021
1022 FreePool (HiiValueArray);
1023
1024 return EFI_SUCCESS;
1025}
1026
1027/**
1028 Base on the type to compare the value.
1029
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.
1033
1034 @retval TRUE The two value are same.
1035 @retval FALSE The two value are different.
1036
1037**/
1038BOOLEAN
1039IsValuesEqual (
1040 IN EFI_IFR_TYPE_VALUE *Value1,
1041 IN EFI_IFR_TYPE_VALUE *Value2,
1042 IN UINT8 Type
1043 )
1044{
1045 switch (Type) {
1046 case EFI_IFR_TYPE_BOOLEAN:
1047 case EFI_IFR_TYPE_NUM_SIZE_8:
1048 return (BOOLEAN) (Value1->u8 == Value2->u8);
1049
1050 case EFI_IFR_TYPE_NUM_SIZE_16:
1051 return (BOOLEAN) (Value1->u16 == Value2->u16);
1052
1053 case EFI_IFR_TYPE_NUM_SIZE_32:
1054 return (BOOLEAN) (Value1->u32 == Value2->u32);
1055
1056 case EFI_IFR_TYPE_NUM_SIZE_64:
1057 return (BOOLEAN) (Value1->u64 == Value2->u64);
1058
1059 default:
1060 ASSERT (FALSE);
1061 return FALSE;
1062 }
1063}
1064
1065/**
1066 Base on the type to set the value.
1067
1068 @param Dest The dest value.
1069 @param Source The source value.
1070 @param Type The value type for above two values.
1071
1072**/
1073VOID
1074SetValuesByType (
1075 OUT EFI_IFR_TYPE_VALUE *Dest,
1076 IN EFI_IFR_TYPE_VALUE *Source,
1077 IN UINT8 Type
1078 )
1079{
1080 switch (Type) {
1081 case EFI_IFR_TYPE_BOOLEAN:
1082 Dest->b = Source->b;
1083 break;
1084
1085 case EFI_IFR_TYPE_NUM_SIZE_8:
1086 Dest->u8 = Source->u8;
1087 break;
1088
1089 case EFI_IFR_TYPE_NUM_SIZE_16:
1090 Dest->u16 = Source->u16;
1091 break;
1092
1093 case EFI_IFR_TYPE_NUM_SIZE_32:
1094 Dest->u32 = Source->u32;
1095 break;
1096
1097 case EFI_IFR_TYPE_NUM_SIZE_64:
1098 Dest->u64 = Source->u64;
1099 break;
1100
1101 default:
1102 ASSERT (FALSE);
1103 break;
1104 }
1105}
1106
1107/**
1108 Get selection for OneOf and OrderedList (Left/Right will be ignored).
1109
1110 @param MenuOption Pointer to the current input menu.
1111
1112 @retval EFI_SUCCESS If Option input is processed successfully
1113 @retval EFI_DEVICE_ERROR If operation fails
1114
1115**/
1116EFI_STATUS
1117GetSelectionInputPopUp (
1118 IN UI_MENU_OPTION *MenuOption
1119 )
1120{
1121 EFI_STATUS Status;
1122 EFI_INPUT_KEY Key;
1123 UINTN Index;
1124 CHAR16 *StringPtr;
1125 CHAR16 *TempStringPtr;
1126 UINTN Index2;
1127 UINTN TopOptionIndex;
1128 UINTN HighlightOptionIndex;
1129 UINTN Start;
1130 UINTN End;
1131 UINTN Top;
1132 UINTN Bottom;
1133 UINTN PopUpMenuLines;
1134 UINTN MenuLinesInView;
1135 UINTN PopUpWidth;
1136 CHAR16 Character;
1137 INT32 SavedAttribute;
1138 BOOLEAN ShowDownArrow;
1139 BOOLEAN ShowUpArrow;
1140 UINTN DimensionsWidth;
1141 LIST_ENTRY *Link;
1142 BOOLEAN OrderedList;
1143 UINT8 *ValueArray;
1144 UINT8 *ReturnValue;
1145 UINT8 ValueType;
1146 EFI_HII_VALUE HiiValue;
1147 DISPLAY_QUESTION_OPTION *OneOfOption;
1148 DISPLAY_QUESTION_OPTION *CurrentOption;
1149 FORM_DISPLAY_ENGINE_STATEMENT *Question;
1150 INTN Result;
1151 EFI_IFR_ORDERED_LIST *OrderList;
1152
1153 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;
1154
1155 ValueArray = NULL;
1156 ValueType = 0;
1157 CurrentOption = NULL;
1158 ShowDownArrow = FALSE;
1159 ShowUpArrow = FALSE;
1160
1161 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);
1162 ASSERT (StringPtr);
1163
1164 ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));
1165
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;
1172 OrderedList = TRUE;
1173 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;
1174 } else {
1175 OrderedList = FALSE;
1176 OrderList = NULL;
1177 }
1178
1179 //
1180 // Calculate Option count
1181 //
1182 PopUpMenuLines = 0;
1183 if (OrderedList) {
1184 AdjustOptionOrder(Question, &PopUpMenuLines);
1185 } else {
1186 Link = GetFirstNode (&Question->OptionListHead);
1187 while (!IsNull (&Question->OptionListHead, Link)) {
1188 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1189 PopUpMenuLines++;
1190 Link = GetNextNode (&Question->OptionListHead, Link);
1191 }
1192 }
1193
1194 //
1195 // Get the number of one of options present and its size
1196 //
1197 PopUpWidth = 0;
1198 HighlightOptionIndex = 0;
1199 Link = GetFirstNode (&Question->OptionListHead);
1200 for (Index = 0; Index < PopUpMenuLines; Index++) {
1201 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1202
1203 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1204 if (StrLen (StringPtr) > PopUpWidth) {
1205 PopUpWidth = StrLen (StringPtr);
1206 }
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)) {
1211 //
1212 // Find current selected Option for OneOf
1213 //
1214 HighlightOptionIndex = Index;
1215 }
1216
1217 Link = GetNextNode (&Question->OptionListHead, Link);
1218 }
1219
1220 //
1221 // Perform popup menu initialization.
1222 //
1223 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;
1224
1225 SavedAttribute = gST->ConOut->Mode->Attribute;
1226 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1227
1228 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {
1229 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;
1230 }
1231
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;
1236
1237 MenuLinesInView = Bottom - Top - 1;
1238 if (MenuLinesInView >= PopUpMenuLines) {
1239 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;
1240 Bottom = Top + PopUpMenuLines + 1;
1241 } else {
1242 ShowDownArrow = TRUE;
1243 }
1244
1245 if (HighlightOptionIndex > (MenuLinesInView - 1)) {
1246 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;
1247 } else {
1248 TopOptionIndex = 0;
1249 }
1250
1251 do {
1252 //
1253 // Clear that portion of the screen
1254 //
1255 ClearLines (Start, End, Top, Bottom, GetPopupColor ());
1256
1257 //
1258 // Draw "One of" pop-up menu
1259 //
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;
1265 } else {
1266 Character = BOXDRAW_HORIZONTAL;
1267 }
1268
1269 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1270 }
1271
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);
1278 }
1279
1280 //
1281 // Move to top Option
1282 //
1283 Link = GetFirstNode (&Question->OptionListHead);
1284 for (Index = 0; Index < TopOptionIndex; Index++) {
1285 Link = GetNextNode (&Question->OptionListHead, Link);
1286 }
1287
1288 //
1289 // Display the One of options
1290 //
1291 Index2 = Top + 1;
1292 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {
1293 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);
1294 Link = GetNextNode (&Question->OptionListHead, Link);
1295
1296 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);
1297 ASSERT (StringPtr != NULL);
1298 //
1299 // If the string occupies multiple lines, truncate it to fit in one line,
1300 // and append a "..." for indication.
1301 //
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"...");
1309 }
1310
1311 if (Index == HighlightOptionIndex) {
1312 //
1313 // Highlight the selected one
1314 //
1315 CurrentOption = OneOfOption;
1316
1317 gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());
1318 PrintStringAt (Start + 2, Index2, StringPtr);
1319 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1320 } else {
1321 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());
1322 PrintStringAt (Start + 2, Index2, StringPtr);
1323 }
1324
1325 Index2++;
1326 FreePool (StringPtr);
1327 }
1328
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;
1334 } else {
1335 Character = BOXDRAW_HORIZONTAL;
1336 }
1337
1338 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1339 }
1340
1341 Character = BOXDRAW_UP_LEFT;
1342 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);
1343
1344 //
1345 // Get User selection
1346 //
1347 Key.UnicodeChar = CHAR_NULL;
1348 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {
1349 Key.ScanCode = gDirection;
1350 gDirection = 0;
1351 goto TheKey;
1352 }
1353
1354 Status = WaitForKeyStroke (&Key);
1355
1356TheKey:
1357 switch (Key.UnicodeChar) {
1358 case '+':
1359 if (OrderedList) {
1360 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1361 //
1362 // Highlight reaches the top of the popup window, scroll one menu item.
1363 //
1364 TopOptionIndex--;
1365 ShowDownArrow = TRUE;
1366 }
1367
1368 if (TopOptionIndex == 0) {
1369 ShowUpArrow = FALSE;
1370 }
1371
1372 if (HighlightOptionIndex > 0) {
1373 HighlightOptionIndex--;
1374
1375 ASSERT (CurrentOption != NULL);
1376 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);
1377 }
1378 }
1379 break;
1380
1381 case '-':
1382 //
1383 // If an ordered list op-code, we will allow for a popup of +/- keys
1384 // to create an ordered list of items
1385 //
1386 if (OrderedList) {
1387 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1388 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
1389 //
1390 // Highlight reaches the bottom of the popup window, scroll one menu item.
1391 //
1392 TopOptionIndex++;
1393 ShowUpArrow = TRUE;
1394 }
1395
1396 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1397 ShowDownArrow = FALSE;
1398 }
1399
1400 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1401 HighlightOptionIndex++;
1402
1403 ASSERT (CurrentOption != NULL);
1404 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);
1405 }
1406 }
1407 break;
1408
1409 case CHAR_NULL:
1410 switch (Key.ScanCode) {
1411 case SCAN_UP:
1412 case SCAN_DOWN:
1413 if (Key.ScanCode == SCAN_UP) {
1414 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {
1415 //
1416 // Highlight reaches the top of the popup window, scroll one menu item.
1417 //
1418 TopOptionIndex--;
1419 ShowDownArrow = TRUE;
1420 }
1421
1422 if (TopOptionIndex == 0) {
1423 ShowUpArrow = FALSE;
1424 }
1425
1426 if (HighlightOptionIndex > 0) {
1427 HighlightOptionIndex--;
1428 }
1429 } else {
1430 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&
1431 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {
1432 //
1433 // Highlight reaches the bottom of the popup window, scroll one menu item.
1434 //
1435 TopOptionIndex++;
1436 ShowUpArrow = TRUE;
1437 }
1438
1439 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {
1440 ShowDownArrow = FALSE;
1441 }
1442
1443 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {
1444 HighlightOptionIndex++;
1445 }
1446 }
1447 break;
1448
1449 case SCAN_ESC:
1450 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1451
1452 //
1453 // Restore link list order for orderedlist
1454 //
1455 if (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) {
1461 break;
1462 }
1463
1464 OneOfOption = ValueToOption (Question, &HiiValue);
1465 if (OneOfOption == NULL) {
1466 return EFI_NOT_FOUND;
1467 }
1468
1469 RemoveEntryList (&OneOfOption->Link);
1470 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);
1471 }
1472 }
1473
1474 return EFI_DEVICE_ERROR;
1475
1476 default:
1477 break;
1478 }
1479
1480 break;
1481
1482 case CHAR_CARRIAGE_RETURN:
1483 //
1484 // return the current selection
1485 //
1486 if (OrderedList) {
1487 ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);
1488 ASSERT (ReturnValue != NULL);
1489 Index = 0;
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);
1494
1495 SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);
1496
1497 Index++;
1498 if (Index > OrderList->MaxContainers) {
1499 break;
1500 }
1501 }
1502 if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {
1503 FreePool (ReturnValue);
1504 return EFI_DEVICE_ERROR;
1505 } else {
1506 gUserInput->InputValue.Buffer = ReturnValue;
1507 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;
1508 Status = EFI_SUCCESS;
1509 }
1510 } else {
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;
1515 } else {
1516 SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);
1517 Status = EFI_SUCCESS;
1518 }
1519 }
1520
1521 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);
1522
1523 return EFI_SUCCESS;
1524
1525 default:
1526 break;
1527 }
1528 } while (TRUE);
1529
1530}
1531
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette