]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/SetupBrowserDxe/InputHandler.c
OvmfPkg/Library/AcpiTimerLib: Modified to support Xen HVM
[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
508b4e77
ED
302 switch (QuestionValue->Value.date.Month) {\r
303 case 2:\r
304 if ((QuestionValue->Value.date.Year % 4) == 0 && \r
c3342aa8
ED
305 ((QuestionValue->Value.date.Year % 100) != 0 || \r
306 (QuestionValue->Value.date.Year % 400) == 0)) {\r
508b4e77
ED
307 Maximum = 29;\r
308 } else {\r
309 Maximum = 28;\r
310 }\r
311 break;\r
312 case 4:\r
313 case 6:\r
314 case 9:\r
315 case 11:\r
316 Maximum = 30;\r
317 break;\r
318 default:\r
319 Maximum = 31;\r
320 break;\r
321 } \r
322\r
7936fb6a 323 EraseLen = 3;\r
324 EditValue = QuestionValue->Value.date.Day;\r
325 break;\r
326\r
327 case 2:\r
328 Maximum = 0xffff;\r
329 EraseLen = 5;\r
330 EditValue = QuestionValue->Value.date.Year;\r
331 break;\r
332\r
333 default:\r
334 break;\r
335 }\r
336 } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
337 Step = 1;\r
338 Minimum = 0;\r
339\r
340 switch (MenuOption->Sequence) {\r
341 case 0:\r
342 Maximum = 23;\r
343 EraseLen = 4;\r
344 EditValue = QuestionValue->Value.time.Hour;\r
345 break;\r
346\r
347 case 1:\r
348 Maximum = 59;\r
349 EraseLen = 3;\r
350 EditValue = QuestionValue->Value.time.Minute;\r
351 break;\r
352\r
353 case 2:\r
354 Maximum = 59;\r
355 EraseLen = 3;\r
356 EditValue = QuestionValue->Value.time.Second;\r
357 break;\r
358\r
359 default:\r
360 break;\r
361 }\r
362 } else {\r
363 //\r
364 // Numeric\r
365 //\r
366 EraseLen = gOptionBlockWidth;\r
367 EditValue = QuestionValue->Value.u64;\r
368 if (Maximum == 0) {\r
369 Maximum = (UINT64) -1;\r
370 }\r
371 }\r
372\r
7936fb6a 373 if ((Question->Operand == EFI_IFR_NUMERIC_OP) &&\r
374 ((Question->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX)) {\r
375 HexInput = TRUE;\r
376 } else {\r
377 HexInput = FALSE;\r
378 }\r
379\r
e24adb18
ED
380 //\r
381 // Enter from "Enter" input, clear the old word showing.\r
382 //\r
7936fb6a 383 if (ManualInput) {\r
e24adb18
ED
384 if (Question->Operand == EFI_IFR_NUMERIC_OP) {\r
385 if (HexInput) {\r
386 InputWidth = Question->StorageWidth * 2;\r
387 } else {\r
388 switch (Question->StorageWidth) {\r
389 case 1:\r
390 InputWidth = 3;\r
391 break;\r
392\r
393 case 2:\r
394 InputWidth = 5;\r
395 break;\r
396\r
397 case 4:\r
398 InputWidth = 10;\r
399 break;\r
400\r
401 case 8:\r
402 InputWidth = 20;\r
403 break;\r
404\r
405 default:\r
406 InputWidth = 0;\r
407 break;\r
408 }\r
409 }\r
7936fb6a 410\r
e24adb18
ED
411 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
412 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
413 ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);\r
414 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
415 InputText[InputWidth + 2] = L'\0';\r
7936fb6a 416\r
e24adb18
ED
417 PrintAt (Column, Row, InputText);\r
418 Column++;\r
419 }\r
7936fb6a 420\r
e24adb18
ED
421 if (Question->Operand == EFI_IFR_DATE_OP) {\r
422 if (MenuOption->Sequence == 2) {\r
423 InputWidth = 4;\r
424 } else {\r
425 InputWidth = 2;\r
426 }\r
7936fb6a 427\r
e24adb18
ED
428 if (MenuOption->Sequence == 0) {\r
429 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
430 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
431 } else {\r
432 SetUnicodeMem (InputText, InputWidth, L' ');\r
433 }\r
434\r
435 if (MenuOption->Sequence == 2) {\r
436 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
437 } else {\r
438 InputText[InputWidth + 1] = DATE_SEPARATOR;\r
439 }\r
440 InputText[InputWidth + 2] = L'\0';\r
441\r
442 PrintAt (Column, Row, InputText);\r
443 if (MenuOption->Sequence == 0) {\r
444 Column++;\r
7936fb6a 445 }\r
446 }\r
447\r
e24adb18
ED
448 if (Question->Operand == EFI_IFR_TIME_OP) {\r
449 InputWidth = 2;\r
7936fb6a 450\r
e24adb18
ED
451 if (MenuOption->Sequence == 0) {\r
452 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
453 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
454 } else {\r
455 SetUnicodeMem (InputText, InputWidth, L' ');\r
456 }\r
457\r
458 if (MenuOption->Sequence == 2) {\r
459 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
460 } else {\r
461 InputText[InputWidth + 1] = TIME_SEPARATOR;\r
462 }\r
463 InputText[InputWidth + 2] = L'\0';\r
464\r
465 PrintAt (Column, Row, InputText);\r
466 if (MenuOption->Sequence == 0) {\r
467 Column++;\r
468 }\r
469 }\r
7936fb6a 470 }\r
471\r
472 //\r
473 // First time we enter this handler, we need to check to see if\r
474 // we were passed an increment or decrement directive\r
475 //\r
476 do {\r
477 Key.UnicodeChar = CHAR_NULL;\r
478 if (gDirection != 0) {\r
479 Key.ScanCode = gDirection;\r
480 gDirection = 0;\r
481 goto TheKey2;\r
482 }\r
483\r
484 Status = WaitForKeyStroke (&Key);\r
485\r
486TheKey2:\r
487 switch (Key.UnicodeChar) {\r
488\r
489 case '+':\r
490 case '-':\r
491 if (Key.UnicodeChar == '+') {\r
492 Key.ScanCode = SCAN_RIGHT;\r
493 } else {\r
494 Key.ScanCode = SCAN_LEFT;\r
495 }\r
496 Key.UnicodeChar = CHAR_NULL;\r
497 goto TheKey2;\r
498\r
499 case CHAR_NULL:\r
500 switch (Key.ScanCode) {\r
501 case SCAN_LEFT:\r
502 case SCAN_RIGHT:\r
e24adb18 503 if (DateOrTime && !ManualInput) {\r
7936fb6a 504 //\r
505 // By setting this value, we will return back to the caller.\r
506 // We need to do this since an auto-refresh will destroy the adjustment\r
507 // based on what the real-time-clock is showing. So we always commit\r
508 // upon changing the value.\r
509 //\r
510 gDirection = SCAN_DOWN;\r
511 }\r
512\r
e24adb18 513 if ((Step != 0) && !ManualInput) {\r
7936fb6a 514 if (Key.ScanCode == SCAN_LEFT) {\r
508b4e77 515 if (EditValue >= Minimum + Step) {\r
7936fb6a 516 EditValue = EditValue - Step;\r
508b4e77 517 } else if (EditValue > Minimum){\r
7936fb6a 518 EditValue = Minimum;\r
508b4e77
ED
519 } else {\r
520 EditValue = Maximum;\r
7936fb6a 521 }\r
522 } else if (Key.ScanCode == SCAN_RIGHT) {\r
508b4e77
ED
523 if (EditValue + Step <= Maximum) {\r
524 EditValue = EditValue + Step;\r
525 } else if (EditValue < Maximum) {\r
7936fb6a 526 EditValue = Maximum;\r
508b4e77
ED
527 } else {\r
528 EditValue = Minimum;\r
7936fb6a 529 }\r
530 }\r
531\r
532 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
533 if (Question->Operand == EFI_IFR_DATE_OP) {\r
534 if (MenuOption->Sequence == 2) {\r
535 //\r
536 // Year\r
537 //\r
7b9b2b92 538 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);\r
7936fb6a 539 } else {\r
540 //\r
541 // Month/Day\r
542 //\r
7b9b2b92 543 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
7936fb6a 544 }\r
545\r
546 if (MenuOption->Sequence == 0) {\r
e35eb8af 547 ASSERT (EraseLen >= 2);\r
7936fb6a 548 FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;\r
549 } else if (MenuOption->Sequence == 1) {\r
e35eb8af 550 ASSERT (EraseLen >= 1);\r
7936fb6a 551 FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;\r
552 }\r
553 } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
7b9b2b92 554 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
7936fb6a 555\r
556 if (MenuOption->Sequence == 0) {\r
e35eb8af 557 ASSERT (EraseLen >= 2);\r
7936fb6a 558 FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;\r
559 } else if (MenuOption->Sequence == 1) {\r
e35eb8af 560 ASSERT (EraseLen >= 1);\r
7936fb6a 561 FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;\r
562 }\r
563 } else {\r
564 QuestionValue->Value.u64 = EditValue;\r
565 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
566 }\r
567\r
f0a1bf11 568 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextColor) | FIELD_BACKGROUND);\r
7936fb6a 569 for (Loop = 0; Loop < EraseLen; Loop++) {\r
570 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
571 }\r
f0a1bf11 572 gST->ConOut->SetAttribute (gST->ConOut, PcdGet8 (PcdBrowserFieldTextHighlightColor) | PcdGet8 (PcdBrowserFieldBackgroundHighlightColor));\r
7936fb6a 573\r
574 if (MenuOption->Sequence == 0) {\r
575 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
576 Column = MenuOption->OptCol + 1;\r
577 }\r
578\r
579 PrintStringAt (Column, Row, FormattedNumber);\r
580\r
581 if (!DateOrTime || MenuOption->Sequence == 2) {\r
582 PrintChar (RIGHT_NUMERIC_DELIMITER);\r
583 }\r
584 }\r
e8e36190 585\r
586 goto EnterCarriageReturn;\r
7936fb6a 587 break;\r
588\r
589 case SCAN_UP:\r
590 case SCAN_DOWN:\r
591 goto EnterCarriageReturn;\r
592\r
593 case SCAN_ESC:\r
594 return EFI_DEVICE_ERROR;\r
595\r
596 default:\r
597 break;\r
598 }\r
599\r
600 break;\r
601\r
602EnterCarriageReturn:\r
603\r
604 case CHAR_CARRIAGE_RETURN:\r
605 //\r
606 // Store Edit value back to Question\r
607 //\r
608 if (Question->Operand == EFI_IFR_DATE_OP) {\r
609 switch (MenuOption->Sequence) {\r
610 case 0:\r
611 QuestionValue->Value.date.Month = (UINT8) EditValue;\r
612 break;\r
613\r
614 case 1:\r
615 QuestionValue->Value.date.Day = (UINT8) EditValue;\r
616 break;\r
617\r
618 case 2:\r
619 QuestionValue->Value.date.Year = (UINT16) EditValue;\r
620 break;\r
621\r
622 default:\r
623 break;\r
624 }\r
625 } else if (Question->Operand == EFI_IFR_TIME_OP) {\r
626 switch (MenuOption->Sequence) {\r
627 case 0:\r
628 QuestionValue->Value.time.Hour = (UINT8) EditValue;\r
629 break;\r
630\r
631 case 1:\r
632 QuestionValue->Value.time.Minute = (UINT8) EditValue;\r
633 break;\r
634\r
635 case 2:\r
636 QuestionValue->Value.time.Second = (UINT8) EditValue;\r
637 break;\r
638\r
639 default:\r
640 break;\r
641 }\r
642 } else {\r
643 //\r
644 // Numeric\r
645 //\r
646 QuestionValue->Value.u64 = EditValue;\r
647 }\r
648\r
649 //\r
650 // Check to see if the Value is something reasonable against consistency limitations.\r
651 // If not, let's kick the error specified.\r
652 //\r
653 Status = ValidateQuestion (FormSet, Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
654 if (EFI_ERROR (Status)) {\r
655 //\r
656 // Input value is not valid, restore Question Value\r
657 //\r
658 GetQuestionValue (FormSet, Form, Question, TRUE);\r
659 } else {\r
660 SetQuestionValue (FormSet, Form, Question, TRUE);\r
661 if (!DateOrTime || (Question->Storage != NULL)) {\r
662 //\r
663 // NV flag is unnecessary for RTC type of Date/Time\r
664 //\r
b18e7050 665 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
7936fb6a 666 }\r
667 }\r
668\r
669 return Status;\r
670 break;\r
671\r
672 case CHAR_BACKSPACE:\r
673 if (ManualInput) {\r
674 if (Count == 0) {\r
675 break;\r
676 }\r
677 //\r
678 // Remove a character\r
679 //\r
680 EditValue = PreviousNumber[Count - 1];\r
b18e7050 681 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
7936fb6a 682 Count--;\r
683 Column--;\r
684 PrintAt (Column, Row, L" ");\r
685 }\r
686 break;\r
687\r
688 default:\r
689 if (ManualInput) {\r
690 if (HexInput) {\r
63d55bb9
LG
691 if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {\r
692 Digital = (UINT8) (Key.UnicodeChar - L'0');\r
693 } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {\r
694 Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);\r
695 } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
696 Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
697 } else {\r
b18e7050 698 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
7936fb6a 699 break;\r
700 }\r
701 } else {\r
702 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
b18e7050 703 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
7936fb6a 704 break;\r
705 }\r
706 }\r
707\r
708 //\r
709 // If Count exceed input width, there is no way more is valid\r
710 //\r
711 if (Count >= InputWidth) {\r
712 break;\r
713 }\r
714 //\r
715 // Someone typed something valid!\r
716 //\r
717 if (Count != 0) {\r
718 if (HexInput) {\r
719 EditValue = LShiftU64 (EditValue, 4) + Digital;\r
720 } else {\r
721 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');\r
722 }\r
723 } else {\r
724 if (HexInput) {\r
725 EditValue = Digital;\r
726 } else {\r
727 EditValue = Key.UnicodeChar - L'0';\r
728 }\r
729 }\r
730\r
731 if (EditValue > Maximum) {\r
b18e7050 732 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, TRUE);\r
40a06b0c 733 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
7936fb6a 734 EditValue = PreviousNumber[Count];\r
735 break;\r
736 } else {\r
b18e7050 737 UpdateStatusBar (Selection, INPUT_ERROR, Question->QuestionFlags, FALSE);\r
7936fb6a 738 }\r
739\r
740 Count++;\r
bc166db3 741 ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));\r
7936fb6a 742 PreviousNumber[Count] = EditValue;\r
743\r
744 PrintCharAt (Column, Row, Key.UnicodeChar);\r
745 Column++;\r
746 }\r
747 break;\r
748 }\r
749 } while (TRUE);\r
750\r
751}\r
752\r
753\r
754/**\r
755 Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
756\r
757 @param Selection Pointer to current selection.\r
758 @param MenuOption Pointer to the current input menu.\r
759\r
760 @retval EFI_SUCCESS If Option input is processed successfully\r
761 @retval EFI_DEVICE_ERROR If operation fails\r
762\r
763**/\r
764EFI_STATUS\r
765GetSelectionInputPopUp (\r
766 IN UI_MENU_SELECTION *Selection,\r
767 IN UI_MENU_OPTION *MenuOption\r
768 )\r
769{\r
770 EFI_STATUS Status;\r
771 EFI_INPUT_KEY Key;\r
772 UINTN Index;\r
773 CHAR16 *StringPtr;\r
774 CHAR16 *TempStringPtr;\r
775 UINTN Index2;\r
776 UINTN TopOptionIndex;\r
777 UINTN HighlightOptionIndex;\r
778 UINTN Start;\r
779 UINTN End;\r
780 UINTN Top;\r
781 UINTN Bottom;\r
782 UINTN PopUpMenuLines;\r
783 UINTN MenuLinesInView;\r
784 UINTN PopUpWidth;\r
785 CHAR16 Character;\r
786 INT32 SavedAttribute;\r
787 BOOLEAN ShowDownArrow;\r
788 BOOLEAN ShowUpArrow;\r
789 UINTN DimensionsWidth;\r
790 LIST_ENTRY *Link;\r
791 BOOLEAN OrderedList;\r
792 UINT8 *ValueArray;\r
d02847d3 793 UINT8 ValueType;\r
7936fb6a 794 EFI_HII_VALUE HiiValue;\r
795 EFI_HII_VALUE *HiiValueArray;\r
796 UINTN OptionCount;\r
797 QUESTION_OPTION *OneOfOption;\r
798 QUESTION_OPTION *CurrentOption;\r
799 FORM_BROWSER_STATEMENT *Question;\r
800\r
801 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
802\r
803 ValueArray = NULL;\r
d02847d3 804 ValueType = 0;\r
7936fb6a 805 CurrentOption = NULL;\r
806 ShowDownArrow = FALSE;\r
807 ShowUpArrow = FALSE;\r
808\r
809 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
810 ASSERT (StringPtr);\r
811\r
812 Question = MenuOption->ThisTag;\r
813 if (Question->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
814 ValueArray = Question->BufferValue;\r
b5a906f4 815 ValueType = Question->ValueType;\r
7936fb6a 816 OrderedList = TRUE;\r
817 } else {\r
818 OrderedList = FALSE;\r
819 }\r
820\r
821 //\r
822 // Calculate Option count\r
823 //\r
824 if (OrderedList) {\r
825 for (Index = 0; Index < Question->MaxContainers; Index++) {\r
d02847d3 826 if (GetArrayData (ValueArray, ValueType, Index) == 0) {\r
7936fb6a 827 break;\r
828 }\r
829 }\r
830\r
831 OptionCount = Index;\r
832 } else {\r
833 OptionCount = 0;\r
834 Link = GetFirstNode (&Question->OptionListHead);\r
835 while (!IsNull (&Question->OptionListHead, Link)) {\r
836 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
837\r
838 OptionCount++;\r
839\r
840 Link = GetNextNode (&Question->OptionListHead, Link);\r
841 }\r
842 }\r
843\r
844 //\r
845 // Prepare HiiValue array\r
846 //\r
847 HiiValueArray = AllocateZeroPool (OptionCount * sizeof (EFI_HII_VALUE));\r
848 ASSERT (HiiValueArray != NULL);\r
849 Link = GetFirstNode (&Question->OptionListHead);\r
850 for (Index = 0; Index < OptionCount; Index++) {\r
851 if (OrderedList) {\r
d02847d3 852 HiiValueArray[Index].Type = ValueType;\r
853 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
7936fb6a 854 } else {\r
855 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
856 CopyMem (&HiiValueArray[Index], &OneOfOption->Value, sizeof (EFI_HII_VALUE));\r
857 Link = GetNextNode (&Question->OptionListHead, Link);\r
858 }\r
859 }\r
860\r
861 //\r
862 // Move Suppressed Option to list tail\r
863 //\r
864 PopUpMenuLines = 0;\r
865 for (Index = 0; Index < OptionCount; Index++) {\r
866 OneOfOption = ValueToOption (Question, &HiiValueArray[OptionCount - Index - 1]);\r
867 if (OneOfOption == NULL) {\r
868 return EFI_NOT_FOUND;\r
869 }\r
870\r
871 RemoveEntryList (&OneOfOption->Link);\r
872\r
873 if ((OneOfOption->SuppressExpression != NULL) &&\r
874 (OneOfOption->SuppressExpression->Result.Value.b)) {\r
875 //\r
876 // This option is suppressed, insert to tail\r
877 //\r
878 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
879 } else {\r
880 //\r
881 // Insert to head\r
882 //\r
883 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);\r
884\r
885 PopUpMenuLines++;\r
886 }\r
887 }\r
888\r
889 //\r
890 // Get the number of one of options present and its size\r
891 //\r
892 PopUpWidth = 0;\r
893 HighlightOptionIndex = 0;\r
894 Link = GetFirstNode (&Question->OptionListHead);\r
895 for (Index = 0; Index < PopUpMenuLines; Index++) {\r
896 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
897\r
898 StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);\r
899 if (StrLen (StringPtr) > PopUpWidth) {\r
900 PopUpWidth = StrLen (StringPtr);\r
901 }\r
f4113e1f 902 FreePool (StringPtr);\r
7936fb6a 903\r
904 if (!OrderedList && CompareHiiValue (&Question->HiiValue, &OneOfOption->Value, NULL) == 0) {\r
905 //\r
906 // Find current selected Option for OneOf\r
907 //\r
908 HighlightOptionIndex = Index;\r
909 }\r
910\r
911 Link = GetNextNode (&Question->OptionListHead, Link);\r
912 }\r
913\r
914 //\r
915 // Perform popup menu initialization.\r
916 //\r
917 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
918\r
919 SavedAttribute = gST->ConOut->Mode->Attribute;\r
920 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
921\r
922 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
923 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
924 }\r
925\r
926 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;\r
927 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
928 Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
929 Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT - 1;\r
930\r
931 MenuLinesInView = Bottom - Top - 1;\r
932 if (MenuLinesInView >= PopUpMenuLines) {\r
933 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
934 Bottom = Top + PopUpMenuLines + 1;\r
935 } else {\r
936 ShowDownArrow = TRUE;\r
937 }\r
938\r
939 if (HighlightOptionIndex > (MenuLinesInView - 1)) {\r
940 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;\r
941 } else {\r
942 TopOptionIndex = 0;\r
943 }\r
944\r
945 do {\r
946 //\r
947 // Clear that portion of the screen\r
948 //\r
949 ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);\r
950\r
951 //\r
952 // Draw "One of" pop-up menu\r
953 //\r
954 Character = BOXDRAW_DOWN_RIGHT;\r
955 PrintCharAt (Start, Top, Character);\r
956 for (Index = Start; Index + 2 < End; Index++) {\r
957 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
958 Character = GEOMETRICSHAPE_UP_TRIANGLE;\r
959 } else {\r
960 Character = BOXDRAW_HORIZONTAL;\r
961 }\r
962\r
963 PrintChar (Character);\r
964 }\r
965\r
966 Character = BOXDRAW_DOWN_LEFT;\r
967 PrintChar (Character);\r
968 Character = BOXDRAW_VERTICAL;\r
969 for (Index = Top + 1; Index < Bottom; Index++) {\r
970 PrintCharAt (Start, Index, Character);\r
971 PrintCharAt (End - 1, Index, Character);\r
972 }\r
973\r
974 //\r
975 // Move to top Option\r
976 //\r
977 Link = GetFirstNode (&Question->OptionListHead);\r
978 for (Index = 0; Index < TopOptionIndex; Index++) {\r
979 Link = GetNextNode (&Question->OptionListHead, Link);\r
980 }\r
981\r
982 //\r
983 // Display the One of options\r
984 //\r
985 Index2 = Top + 1;\r
986 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {\r
987 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
988 Link = GetNextNode (&Question->OptionListHead, Link);\r
989\r
990 StringPtr = GetToken (OneOfOption->Text, MenuOption->Handle);\r
991 //\r
992 // If the string occupies multiple lines, truncate it to fit in one line,\r
993 // and append a "..." for indication.\r
994 //\r
995 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
996 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
997 ASSERT ( TempStringPtr != NULL );\r
998 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
f4113e1f 999 FreePool (StringPtr);\r
7936fb6a 1000 StringPtr = TempStringPtr;\r
1001 StrCat (StringPtr, L"...");\r
1002 }\r
1003\r
1004 if (Index == HighlightOptionIndex) {\r
1005 //\r
1006 // Highlight the selected one\r
1007 //\r
1008 CurrentOption = OneOfOption;\r
1009\r
1010 gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);\r
1011 PrintStringAt (Start + 2, Index2, StringPtr);\r
1012 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1013 } else {\r
1014 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1015 PrintStringAt (Start + 2, Index2, StringPtr);\r
1016 }\r
1017\r
1018 Index2++;\r
f4113e1f 1019 FreePool (StringPtr);\r
7936fb6a 1020 }\r
1021\r
1022 Character = BOXDRAW_UP_RIGHT;\r
1023 PrintCharAt (Start, Bottom, Character);\r
1024 for (Index = Start; Index + 2 < End; Index++) {\r
1025 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1026 Character = GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1027 } else {\r
1028 Character = BOXDRAW_HORIZONTAL;\r
1029 }\r
1030\r
1031 PrintChar (Character);\r
1032 }\r
1033\r
1034 Character = BOXDRAW_UP_LEFT;\r
1035 PrintChar (Character);\r
1036\r
1037 //\r
1038 // Get User selection\r
1039 //\r
1040 Key.UnicodeChar = CHAR_NULL;\r
1041 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1042 Key.ScanCode = gDirection;\r
1043 gDirection = 0;\r
1044 goto TheKey;\r
1045 }\r
1046\r
1047 Status = WaitForKeyStroke (&Key);\r
1048\r
1049TheKey:\r
1050 switch (Key.UnicodeChar) {\r
1051 case '+':\r
1052 if (OrderedList) {\r
1053 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1054 //\r
1055 // Highlight reaches the top of the popup window, scroll one menu item.\r
1056 //\r
1057 TopOptionIndex--;\r
1058 ShowDownArrow = TRUE;\r
1059 }\r
1060\r
1061 if (TopOptionIndex == 0) {\r
1062 ShowUpArrow = FALSE;\r
1063 }\r
1064\r
1065 if (HighlightOptionIndex > 0) {\r
1066 HighlightOptionIndex--;\r
1067\r
40a06b0c 1068 ASSERT (CurrentOption != NULL);\r
7936fb6a 1069 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);\r
1070 }\r
1071 }\r
1072 break;\r
1073\r
1074 case '-':\r
1075 //\r
1076 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1077 // to create an ordered list of items\r
1078 //\r
1079 if (OrderedList) {\r
1080 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1081 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1082 //\r
1083 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1084 //\r
1085 TopOptionIndex++;\r
1086 ShowUpArrow = TRUE;\r
1087 }\r
1088\r
1089 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1090 ShowDownArrow = FALSE;\r
1091 }\r
1092\r
1093 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1094 HighlightOptionIndex++;\r
1095\r
40a06b0c 1096 ASSERT (CurrentOption != NULL);\r
7936fb6a 1097 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);\r
1098 }\r
1099 }\r
1100 break;\r
1101\r
1102 case CHAR_NULL:\r
1103 switch (Key.ScanCode) {\r
1104 case SCAN_UP:\r
1105 case SCAN_DOWN:\r
1106 if (Key.ScanCode == SCAN_UP) {\r
1107 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1108 //\r
1109 // Highlight reaches the top of the popup window, scroll one menu item.\r
1110 //\r
1111 TopOptionIndex--;\r
1112 ShowDownArrow = TRUE;\r
1113 }\r
1114\r
1115 if (TopOptionIndex == 0) {\r
1116 ShowUpArrow = FALSE;\r
1117 }\r
1118\r
1119 if (HighlightOptionIndex > 0) {\r
1120 HighlightOptionIndex--;\r
1121 }\r
1122 } else {\r
1123 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1124 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1125 //\r
1126 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1127 //\r
1128 TopOptionIndex++;\r
1129 ShowUpArrow = TRUE;\r
1130 }\r
1131\r
1132 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1133 ShowDownArrow = FALSE;\r
1134 }\r
1135\r
1136 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1137 HighlightOptionIndex++;\r
1138 }\r
1139 }\r
1140 break;\r
1141\r
1142 case SCAN_ESC:\r
1143 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1144\r
1145 //\r
1146 // Restore link list order for orderedlist\r
1147 //\r
1148 if (OrderedList) {\r
d02847d3 1149 HiiValue.Type = ValueType;\r
7936fb6a 1150 HiiValue.Value.u64 = 0;\r
1151 for (Index = 0; Index < Question->MaxContainers; Index++) {\r
d02847d3 1152 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1153 if (HiiValue.Value.u64 == 0) {\r
7936fb6a 1154 break;\r
1155 }\r
1156\r
1157 OneOfOption = ValueToOption (Question, &HiiValue);\r
1158 if (OneOfOption == NULL) {\r
1159 return EFI_NOT_FOUND;\r
1160 }\r
1161\r
1162 RemoveEntryList (&OneOfOption->Link);\r
1163 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
1164 }\r
1165 }\r
1166\r
f4113e1f 1167 FreePool (HiiValueArray);\r
7936fb6a 1168 return EFI_DEVICE_ERROR;\r
1169\r
1170 default:\r
1171 break;\r
1172 }\r
1173\r
1174 break;\r
1175\r
1176 case CHAR_CARRIAGE_RETURN:\r
1177 //\r
1178 // return the current selection\r
1179 //\r
1180 if (OrderedList) {\r
1181 Index = 0;\r
1182 Link = GetFirstNode (&Question->OptionListHead);\r
1183 while (!IsNull (&Question->OptionListHead, Link)) {\r
1184 OneOfOption = QUESTION_OPTION_FROM_LINK (Link);\r
1185\r
d02847d3 1186 SetArrayData (ValueArray, ValueType, Index, OneOfOption->Value.Value.u64);\r
7936fb6a 1187\r
1188 Index++;\r
1189 if (Index > Question->MaxContainers) {\r
1190 break;\r
1191 }\r
1192\r
1193 Link = GetNextNode (&Question->OptionListHead, Link);\r
1194 }\r
1195 } else {\r
40a06b0c 1196 ASSERT (CurrentOption != NULL);\r
7936fb6a 1197 CopyMem (&Question->HiiValue, &CurrentOption->Value, sizeof (EFI_HII_VALUE));\r
1198 }\r
1199\r
1200 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
f4113e1f 1201 FreePool (HiiValueArray);\r
7936fb6a 1202\r
1203 Status = ValidateQuestion (Selection->FormSet, Selection->Form, Question, EFI_HII_EXPRESSION_INCONSISTENT_IF);\r
1204 if (EFI_ERROR (Status)) {\r
1205 //\r
1206 // Input value is not valid, restore Question Value\r
1207 //\r
1208 GetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
1209 } else {\r
1210 SetQuestionValue (Selection->FormSet, Selection->Form, Question, TRUE);\r
b18e7050 1211 UpdateStatusBar (Selection, NV_UPDATE_REQUIRED, Question->QuestionFlags, TRUE);\r
7936fb6a 1212 }\r
1213\r
1214 return Status;\r
1215\r
1216 default:\r
1217 break;\r
1218 }\r
1219 } while (TRUE);\r
1220\r
1221}\r
1222\r
1223/**\r
1224 Wait for a key to be pressed by user.\r
1225\r
1226 @param Key The key which is pressed by user.\r
1227\r
1228 @retval EFI_SUCCESS The function always completed successfully.\r
1229\r
1230**/\r
1231EFI_STATUS\r
1232WaitForKeyStroke (\r
1233 OUT EFI_INPUT_KEY *Key\r
1234 )\r
1235{\r
1236 EFI_STATUS Status;\r
1237\r
1238 do {\r
1239 UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0, 0);\r
1240 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
1241 } while (EFI_ERROR(Status));\r
1242\r
1243 return Status;\r
1244}\r