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