VirtualBox

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

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

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