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