]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c
Correct all header files for doxygen format and correct the license issue for VgaClas...
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / SetupBrowserDxe / InputHandler.c
CommitLineData
3db51098 1/**@file\r
2 Implementation for handling user input from the User Interface\r
103b6520 3\r
3db51098 4Copyright (c) 2006, Intel Corporation\r
103b6520 5All rights reserved. This program and the accompanying materials\r
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
3db51098 13**/\r
103b6520 14\r
103b6520 15#include "Setup.h"\r
16#include "Ui.h"\r
17#include "Colors.h"\r
18\r
19#define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))\r
20\r
21EFI_STATUS\r
22ReadString(\r
23 IN UI_MENU_OPTION *MenuOption,\r
24 OUT CHAR16 *StringPtr\r
25 )\r
26{\r
27 EFI_STATUS Status;\r
28 EFI_INPUT_KEY Key;\r
29 CHAR16 NullCharacter;\r
30 UINTN ScreenSize;\r
31 EFI_TAG *Tag;\r
32 CHAR16 Space[2];\r
33 CHAR16 KeyPad[2];\r
34 BOOLEAN SelectionComplete;\r
35 CHAR16 *TempString;\r
36 CHAR16 *BufferedString;\r
37 UINTN Index;\r
38 UINTN Count;\r
39 UINTN Start;\r
40 UINTN Top;\r
41 CHAR16 *PromptForDataString;\r
42 UINTN DimensionsWidth;\r
43 UINTN DimensionsHeight;\r
44 BOOLEAN CursorVisible;\r
45\r
46 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
47 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
48\r
49 PromptForDataString = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
50\r
51 NullCharacter = CHAR_NULL;\r
52 ScreenSize = GetStringWidth (PromptForDataString) / 2;\r
53 Tag = MenuOption->ThisTag;\r
54 Space[0] = L' ';\r
55 Space[1] = CHAR_NULL;\r
56 SelectionComplete = FALSE;\r
57\r
58 TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
59 ASSERT (TempString);\r
60\r
61 if (ScreenSize < (Tag->Maximum / (UINTN) 2)) {\r
62 ScreenSize = Tag->Maximum / 2;\r
63 }\r
64\r
65 if ((ScreenSize + 2) > DimensionsWidth) {\r
66 ScreenSize = DimensionsWidth - 2;\r
67 }\r
68\r
69 BufferedString = AllocateZeroPool (ScreenSize * 2);\r
70 ASSERT (BufferedString);\r
71\r
72 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
73 Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;\r
74\r
75 //\r
76 // Display prompt for string\r
77 //\r
78 CreatePopUp (ScreenSize, 4, &NullCharacter, PromptForDataString, Space, &NullCharacter);\r
79\r
80 FreePool (PromptForDataString);\r
81\r
82 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
83\r
84 CursorVisible = gST->ConOut->Mode->CursorVisible;\r
85 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
86\r
87 do {\r
88 Status = WaitForKeyStroke (&Key);\r
89\r
90 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
91 switch (Key.UnicodeChar) {\r
92 case CHAR_NULL:\r
93 switch (Key.ScanCode) {\r
94 case SCAN_LEFT:\r
95 break;\r
96\r
97 case SCAN_RIGHT:\r
98 break;\r
99\r
100 case SCAN_ESC:\r
101 FreePool (TempString);\r
102 FreePool (BufferedString);\r
103 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
104 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
105 return EFI_DEVICE_ERROR;\r
106\r
107 default:\r
108 break;\r
109 }\r
110\r
111 break;\r
112\r
113 case CHAR_CARRIAGE_RETURN:\r
114 if (GetStringWidth (StringPtr) >= MenuOption->ThisTag->Minimum) {\r
115 SelectionComplete = TRUE;\r
116 FreePool (TempString);\r
117 FreePool (BufferedString);\r
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_SUCCESS;\r
121 } else {\r
122 ScreenSize = GetStringWidth (gMiniString) / 2;\r
123 CreatePopUp (ScreenSize, 4, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);\r
124 //\r
125 // Simply create a popup to tell the user that they had typed in too few characters.\r
126 // To save code space, we can then treat this as an error and return back to the menu.\r
127 //\r
128 do {\r
129 Status = WaitForKeyStroke (&Key);\r
130 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
131 FreePool (TempString);\r
132 FreePool (BufferedString);\r
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_DEVICE_ERROR;\r
136 }\r
137\r
138 break;\r
139\r
140 case CHAR_BACKSPACE:\r
141 if (StringPtr[0] != CHAR_NULL) {\r
142 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
143 TempString[Index] = StringPtr[Index];\r
144 }\r
145 //\r
146 // Effectively truncate string by 1 character\r
147 //\r
148 TempString[Index - 1] = CHAR_NULL;\r
149 StrCpy (StringPtr, TempString);\r
150 }\r
151\r
152 default:\r
153 //\r
154 // If it is the beginning of the string, don't worry about checking maximum limits\r
155 //\r
156 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
157 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
158 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
159 } else if ((GetStringWidth (StringPtr) < MenuOption->ThisTag->Maximum) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
160 KeyPad[0] = Key.UnicodeChar;\r
161 KeyPad[1] = CHAR_NULL;\r
162 StrCat (StringPtr, KeyPad);\r
163 StrCat (TempString, KeyPad);\r
164 }\r
165 //\r
166 // If the width of the input string is now larger than the screen, we nee to\r
167 // adjust the index to start printing portions of the string\r
168 //\r
169 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
170\r
171 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
172\r
173 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
174 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
175 } else {\r
176 Index = 0;\r
177 }\r
178\r
179 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
180 BufferedString[Count] = StringPtr[Index];\r
181 }\r
182\r
183 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
184 break;\r
185 }\r
186\r
187 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
188 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
189 } while (!SelectionComplete);\r
190 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
191 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
192 return Status;\r
193}\r
194\r
195EFI_STATUS\r
196ReadPassword (\r
197 IN UI_MENU_OPTION *MenuOption,\r
198 IN BOOLEAN PromptForPassword,\r
199 IN EFI_TAG *Tag,\r
200 IN EFI_IFR_DATA_ARRAY *PageData,\r
201 IN BOOLEAN SecondEntry,\r
202 IN EFI_FILE_FORM_TAGS *FileFormTags,\r
203 OUT CHAR16 *StringPtr\r
204 )\r
205{\r
206 EFI_STATUS Status;\r
207 UINTN ScreenSize;\r
208 CHAR16 NullCharacter;\r
209 CHAR16 Space[2];\r
210 EFI_INPUT_KEY Key;\r
211 CHAR16 KeyPad[2];\r
212 UINTN Index;\r
213 UINTN Start;\r
214 UINTN Top;\r
215 CHAR16 *TempString;\r
216 CHAR16 *TempString2;\r
217 BOOLEAN Confirmation;\r
218 BOOLEAN ConfirmationComplete;\r
219 EFI_HII_CALLBACK_PACKET *Packet;\r
220 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;\r
221 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
222 UINTN DimensionsWidth;\r
223 UINTN DimensionsHeight;\r
224 EFI_IFR_DATA_ENTRY *DataEntry;\r
225 UINTN WidthOfString;\r
226\r
227 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
228 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
229\r
230 VariableDefinition = NULL;\r
231 NullCharacter = CHAR_NULL;\r
232 Space[0] = L' ';\r
233 Space[1] = CHAR_NULL;\r
234 Confirmation = FALSE;\r
235 ConfirmationComplete = FALSE;\r
236 Status = EFI_SUCCESS;\r
237 FormCallback = NULL;\r
238 Packet = NULL;\r
239\r
240 //\r
241 // Remember that dynamic pages in an environment where all pages are not\r
242 // dynamic require us to call back to the user to give them an opportunity\r
243 // to register fresh information in the HII database so that we can extract it.\r
244 //\r
245 Status = gBS->HandleProtocol (\r
246 (VOID *) (UINTN) MenuOption->Tags[0].CallbackHandle,\r
247 &gEfiFormCallbackProtocolGuid,\r
248 (VOID **) &FormCallback\r
249 );\r
250\r
251 TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
252 TempString2 = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
253\r
254 ASSERT (TempString);\r
255 ASSERT (TempString2);\r
256\r
257 if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
258 //\r
259 // Password requires a callback to determine if a password exists\r
260 //\r
261 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
262 DataEntry->OpCode = EFI_IFR_PASSWORD_OP;\r
263 DataEntry->Length = 3;\r
264\r
265 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
266\r
267 //\r
268 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)\r
269 //\r
270 DataEntry->Data = (VOID *) (UINTN) (UINT8) (0 + SecondEntry * 2);\r
271 PageData->NvRamMap = VariableDefinition->NvRamMap;\r
272\r
273 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
274 Status = FormCallback->Callback (\r
275 FormCallback,\r
276 Tag->Key,\r
277 PageData,\r
278 &Packet\r
279 );\r
280 }\r
281 //\r
282 // If error on return, continue with the reading of a typed in password to verify user knows password\r
283 // If no error, there is no password set, so prompt for new password\r
284 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error\r
285 //\r
286 if (!EFI_ERROR (Status)) {\r
287 PromptForPassword = FALSE;\r
288\r
289 //\r
290 // Simulate this as the second entry into this routine for an interactive behavior\r
291 //\r
292 SecondEntry = TRUE;\r
293 } else if (Status == EFI_NOT_READY) {\r
294Error:\r
295 if (Packet != NULL) {\r
296 //\r
297 // Upon error, we will likely receive a string to print out\r
298 // Display error popup\r
299 //\r
300 WidthOfString = GetStringWidth (Packet->String);\r
301 ScreenSize = EFI_MAX(WidthOfString, GetStringWidth (gPressEnter)) / 2;\r
302 CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);\r
303 FreePool (Packet);\r
304\r
305 do {\r
306 Status = WaitForKeyStroke (&Key);\r
307 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
308 }\r
309\r
310 Status = EFI_NOT_READY;\r
311 goto Done;\r
312 }\r
313 }\r
314\r
315 do {\r
316 //\r
317 // Display PopUp Screen\r
318 //\r
319 ScreenSize = GetStringWidth (gPromptForNewPassword) / 2;\r
320 if (GetStringWidth (gConfirmPassword) / 2 > ScreenSize) {\r
321 ScreenSize = GetStringWidth (gConfirmPassword) / 2;\r
322 }\r
323\r
324 Start = (DimensionsWidth - ScreenSize - 4) / 2 + gScreenDimensions.LeftColumn + 2;\r
325 Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;\r
326\r
327 if (!Confirmation) {\r
328 if (PromptForPassword) {\r
329 CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForPassword, Space, &NullCharacter);\r
330 } else {\r
331 CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForNewPassword, Space, &NullCharacter);\r
332 }\r
333 } else {\r
334 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmPassword, Space, &NullCharacter);\r
335 StringPtr[0] = CHAR_NULL;\r
336 }\r
337\r
338 do {\r
339 Status = WaitForKeyStroke (&Key);\r
340\r
341 switch (Key.UnicodeChar) {\r
342 case CHAR_NULL:\r
343 if (Key.ScanCode == SCAN_ESC) {\r
344 return EFI_NOT_READY;\r
345 }\r
346\r
347 ConfirmationComplete = FALSE;\r
348 break;\r
349\r
350 case CHAR_CARRIAGE_RETURN:\r
351 if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
352 //\r
353 // User just typed a string in\r
354 //\r
355 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
356 DataEntry->OpCode = EFI_IFR_PASSWORD_OP;\r
357\r
358 //\r
359 // If the user just typed in a password, Data = 1\r
360 // If the user just typed in a password to confirm the previous password, Data = 2\r
361 //\r
362 if (!Confirmation) {\r
363 DataEntry->Length = 3;\r
364 DataEntry->Data = (VOID *) (UINTN) (UINT8) (1 + SecondEntry * 2);\r
365\r
366 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
367 Status = FormCallback->Callback (\r
368 FormCallback,\r
369 Tag->Key,\r
370 PageData,\r
371 &Packet\r
372 );\r
373 }\r
374\r
375 DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);\r
376 DataEntry->Data = (VOID *) TempString;\r
377 } else {\r
378 DataEntry->Length = 3;\r
379 DataEntry->Data = (VOID *) (UINTN) (UINT8) (2 + SecondEntry * 2);\r
380\r
381 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
382 Status = FormCallback->Callback (\r
383 FormCallback,\r
384 Tag->Key,\r
385 PageData,\r
386 &Packet\r
387 );\r
388 }\r
389\r
390 DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);\r
391 DataEntry->Data = (VOID *) TempString2;\r
392 }\r
393\r
394 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
395 Status = FormCallback->Callback (\r
396 FormCallback,\r
397 Tag->Key,\r
398 PageData,\r
399 &Packet\r
400 );\r
401 }\r
402 //\r
403 // If this was the confirmation round of callbacks\r
404 // and an error comes back, display an error\r
405 //\r
406 if (Confirmation) {\r
407 if (EFI_ERROR (Status)) {\r
408 if (Packet->String == NULL) {\r
409 WidthOfString = GetStringWidth (gConfirmError);\r
410 ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2;\r
411 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);\r
412 } else {\r
413 WidthOfString = GetStringWidth (Packet->String);\r
414 ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2;\r
415 CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);\r
416 FreePool (Packet);\r
417 }\r
418\r
419 StringPtr[0] = CHAR_NULL;\r
420 do {\r
421 Status = WaitForKeyStroke (&Key);\r
422\r
423 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
424 Status = EFI_NOT_READY;\r
425 goto Done;\r
426 }\r
427 } while (1);\r
428 } else {\r
429 Status = EFI_NOT_READY;\r
430 goto Done;\r
431 }\r
432 } else {\r
433 //\r
434 // User typed a string in and it wasn't valid somehow from the callback\r
435 // For instance, callback may have said that some invalid characters were contained in the string\r
436 //\r
437 if (Status == EFI_NOT_READY) {\r
438 goto Error;\r
439 }\r
440\r
441 if (PromptForPassword && EFI_ERROR (Status)) {\r
442 Status = EFI_DEVICE_ERROR;\r
443 goto Done;\r
444 }\r
445 }\r
446 }\r
447\r
448 if (Confirmation) {\r
449 //\r
450 // Compare tempstring and tempstring2, if the same, return with StringPtr success\r
451 // Otherwise, kick and error box, and return an error\r
452 //\r
453 if (StrCmp (TempString, TempString2) == 0) {\r
454 Status = EFI_SUCCESS;\r
455 goto Done;\r
456 } else {\r
457 WidthOfString = GetStringWidth (gConfirmError);\r
458 ScreenSize = EFI_MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2;\r
459 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);\r
460 StringPtr[0] = CHAR_NULL;\r
461 do {\r
462 Status = WaitForKeyStroke (&Key);\r
463 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
464 Status = EFI_DEVICE_ERROR;\r
465 goto Done;\r
466 }\r
467 } while (1);\r
468 }\r
469 }\r
470\r
471 if (PromptForPassword) {\r
472 //\r
473 // I was asked for a password, return it back in StringPtr\r
474 //\r
475 Status = EFI_SUCCESS;\r
476 goto Done;\r
477 } else {\r
478 //\r
479 // If the two passwords were not the same kick an error popup\r
480 //\r
481 Confirmation = TRUE;\r
482 ConfirmationComplete = TRUE;\r
483 break;\r
484 }\r
485\r
486 case CHAR_BACKSPACE:\r
487 if (StringPtr[0] != CHAR_NULL) {\r
488 if (!Confirmation) {\r
489 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
490 TempString[Index] = StringPtr[Index];\r
491 }\r
492 //\r
493 // Effectively truncate string by 1 character\r
494 //\r
495 TempString[Index - 1] = CHAR_NULL;\r
496 StrCpy (StringPtr, TempString);\r
497 } else {\r
498 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
499 TempString2[Index] = StringPtr[Index];\r
500 }\r
501 //\r
502 // Effectively truncate string by 1 character\r
503 //\r
504 TempString2[Index - 1] = CHAR_NULL;\r
505 StrCpy (StringPtr, TempString2);\r
506 }\r
507\r
508 ConfirmationComplete = FALSE;\r
509 } else {\r
510 ConfirmationComplete = FALSE;\r
511 }\r
512\r
513 //\r
514 // Must be a character we are interested in!\r
515 //\r
516 default:\r
517 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
518 if (!Confirmation) {\r
519 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
520 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
521 } else {\r
522 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
523 StrnCpy (TempString2, &Key.UnicodeChar, 1);\r
524 ConfirmationComplete = FALSE;\r
525 }\r
526 } else if ((GetStringWidth (StringPtr) / 2 <= (UINTN) (MenuOption->ThisTag->Maximum - 1) / 2) &&\r
527 (Key.UnicodeChar != CHAR_BACKSPACE)\r
528 ) {\r
529 KeyPad[0] = Key.UnicodeChar;\r
530 KeyPad[1] = CHAR_NULL;\r
531 if (!Confirmation) {\r
532 StrCat (StringPtr, KeyPad);\r
533 StrCat (TempString, KeyPad);\r
534 } else {\r
535 StrCat (StringPtr, KeyPad);\r
536 StrCat (TempString2, KeyPad);\r
537 }\r
538 }\r
539\r
540 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
541 for (Index = 1; Index < ScreenSize; Index++) {\r
542 PrintCharAt (Start + Index, Top + 3, L' ');\r
543 }\r
544\r
545 gST->ConOut->SetCursorPosition (\r
546 gST->ConOut,\r
547 (DimensionsWidth - GetStringWidth (StringPtr) / 2) / 2 + gScreenDimensions.LeftColumn,\r
548 Top + 3\r
549 );\r
550 for (Index = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++) {\r
551 PrintChar (L'*');\r
552 }\r
553\r
554 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
555 break;\r
556 }\r
557 //\r
558 // end switch\r
559 //\r
560 } while (!ConfirmationComplete);\r
561\r
562 } while (1);\r
563\r
564Done:\r
565 FreePool (TempString);\r
566 FreePool (TempString2);\r
567 return Status;\r
568}\r
569\r
570VOID\r
571EncodePassword (\r
572 IN CHAR16 *Password,\r
573 IN UINT8 MaxSize\r
574 )\r
575{\r
576 UINTN Index;\r
577 UINTN Loop;\r
578 CHAR16 *Buffer;\r
579 CHAR16 *Key;\r
580\r
581 Key = (CHAR16 *) L"MAR10648567";\r
582 Buffer = AllocateZeroPool (MaxSize);\r
583\r
584 ASSERT (Buffer);\r
585\r
586 for (Index = 0; Key[Index] != 0; Index++) {\r
587 for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) {\r
588 Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]);\r
589 }\r
590 }\r
591\r
592 CopyMem (Password, Buffer, MaxSize);\r
593\r
594 FreePool (Buffer);\r
595 return ;\r
596}\r
597\r
598EFI_STATUS\r
599GetNumericInput (\r
600 IN UI_MENU_OPTION *MenuOption,\r
601 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
602 IN BOOLEAN ManualInput,\r
603 IN EFI_TAG *Tag,\r
604 IN UINTN NumericType,\r
605 OUT UINT16 *Value\r
606 )\r
607/*++\r
608\r
609Routine Description:\r
610\r
611 This routine reads a numeric value from the user input.\r
612\r
613Arguments:\r
614\r
615 MenuOption - Pointer to the current input menu.\r
616\r
617 FileFormTagsHead - Pointer to the root of formset.\r
618\r
619 ManualInput - If the input is manual or not.\r
620\r
621 Tag - Pointer to all the attributes and values associated with a tag.\r
622\r
623 Value - Pointer to the numeric value that is going to be read.\r
624\r
625Returns:\r
626\r
627 EFI_SUCCESS - If numerical input is read successfully\r
628 EFI_DEVICE_ERROR - If operation fails\r
629\r
630--*/\r
631{\r
632 EFI_INPUT_KEY Key;\r
633 BOOLEAN SelectionComplete;\r
634 UINTN Column;\r
635 UINTN Row;\r
636 CHAR16 FormattedNumber[6];\r
637 UINTN PreviousNumber[6];\r
638 INTN Number;\r
639 UINTN Count;\r
640 UINT16 BackupValue;\r
641 STRING_REF PopUp;\r
642 CHAR16 NullCharacter;\r
643 CHAR16 *StringPtr;\r
644 EFI_FILE_FORM_TAGS *FileFormTags;\r
645 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
646 UINTN Loop;\r
647\r
648 NullCharacter = CHAR_NULL;\r
649 StringPtr = NULL;\r
650 Column = MenuOption->OptCol;\r
651 Row = MenuOption->Row;\r
652 Number = 0;\r
653 PreviousNumber[0] = 0;\r
654 Count = 0;\r
655 SelectionComplete = FALSE;\r
656 BackupValue = Tag->Value;\r
657 FileFormTags = FileFormTagsHead;\r
658\r
659 if (ManualInput) {\r
660 PrintAt (Column, Row, (CHAR16 *) L"[ ]");\r
661 Column++;\r
662 if (Tag->Operand != EFI_IFR_TIME_OP) {\r
663 *Value = BackupValue;\r
664 }\r
665 }\r
666 //\r
667 // First time we enter this handler, we need to check to see if\r
668 // we were passed an increment or decrement directive\r
669 //\r
670 do {\r
671 Key.UnicodeChar = CHAR_NULL;\r
672 if (gDirection != 0) {\r
673 Key.ScanCode = gDirection;\r
674 gDirection = 0;\r
675 goto TheKey2;\r
676 }\r
677\r
678 WaitForKeyStroke (&Key);\r
679\r
680TheKey2:\r
681 switch (Key.UnicodeChar) {\r
682 case '+':\r
683 case '-':\r
684 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
685 Key.UnicodeChar = CHAR_NULL;\r
686 if (Key.UnicodeChar == '+') {\r
687 Key.ScanCode = SCAN_RIGHT;\r
688 } else {\r
689 Key.ScanCode = SCAN_LEFT;\r
690 }\r
691\r
692 goto TheKey2;\r
693 }\r
694 break;\r
695\r
696 case CHAR_NULL:\r
697 switch (Key.ScanCode) {\r
698 case SCAN_LEFT:\r
699 case SCAN_RIGHT:\r
700 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
701 //\r
702 // By setting this value, we will return back to the caller.\r
703 // We need to do this since an auto-refresh will destroy the adjustment\r
704 // based on what the real-time-clock is showing. So we always commit\r
705 // upon changing the value.\r
706 //\r
707 gDirection = SCAN_DOWN;\r
708 }\r
709\r
710 if (!ManualInput) {\r
711 Tag->Value = *Value;\r
712 if (Key.ScanCode == SCAN_LEFT) {\r
713 Number = *Value - Tag->Step;\r
714 if (Number < Tag->Minimum) {\r
715 Number = Tag->Minimum;\r
716 }\r
717 } else if (Key.ScanCode == SCAN_RIGHT) {\r
718 Number = *Value + Tag->Step;\r
719 if (Number > Tag->Maximum) {\r
720 Number = Tag->Maximum;\r
721 }\r
722 }\r
723\r
724 Tag->Value = (UINT16) Number;\r
725 *Value = (UINT16) Number;\r
726 UnicodeValueToString (\r
727 FormattedNumber,\r
728 FALSE,\r
729 (UINTN) Number,\r
730 (sizeof (FormattedNumber) / sizeof (FormattedNumber[0]))\r
731 );\r
732 Number = (UINT16) GetStringWidth (FormattedNumber);\r
733\r
734 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
735 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
736 for (Loop = 0; Loop < (UINTN) ((Number >= 8) ? 4 : 2); Loop++) {\r
737 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");\r
738 }\r
739 } else {\r
740 for (Loop = 0; Loop < gOptionBlockWidth; Loop++) {\r
741 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");\r
742 }\r
743 }\r
744\r
745 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
746\r
747 if ((MenuOption->Col + gPromptBlockWidth + 1) == MenuOption->OptCol) {\r
748 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
749 Column = MenuOption->OptCol + 1;\r
750 }\r
751 //\r
752 // If Number looks like "3", convert it to "03/"\r
753 //\r
754 if (Number == 4 && (NumericType == DATE_NUMERIC)) {\r
755 FormattedNumber[3] = FormattedNumber[1];\r
756 FormattedNumber[2] = DATE_SEPARATOR;\r
757 FormattedNumber[1] = FormattedNumber[0];\r
758 FormattedNumber[0] = L'0';\r
759 Number = 8;\r
760 }\r
761 //\r
762 // If Number looks like "13", convert it to "13/"\r
763 //\r
764 if (Number == 6 && (NumericType == DATE_NUMERIC)) {\r
765 FormattedNumber[3] = FormattedNumber[2];\r
766 FormattedNumber[2] = DATE_SEPARATOR;\r
767 Number = 8;\r
768 }\r
769\r
770 if (Number == 4 &&\r
771 (NumericType == TIME_NUMERIC) &&\r
772 (MenuOption->Col + gPromptBlockWidth + 8) != MenuOption->OptCol\r
773 ) {\r
774 FormattedNumber[3] = FormattedNumber[1];\r
775 FormattedNumber[2] = TIME_SEPARATOR;\r
776 FormattedNumber[1] = FormattedNumber[0];\r
777 FormattedNumber[0] = L'0';\r
778 Number = 8;\r
779 }\r
780\r
781 if (Number == 4 &&\r
782 (NumericType == TIME_NUMERIC) &&\r
783 (MenuOption->Col + gPromptBlockWidth + 8) == MenuOption->OptCol\r
784 ) {\r
785 FormattedNumber[3] = FormattedNumber[1];\r
786 FormattedNumber[2] = RIGHT_NUMERIC_DELIMITER;\r
787 FormattedNumber[1] = FormattedNumber[0];\r
788 FormattedNumber[0] = L'0';\r
789 Number = 8;\r
790 }\r
791\r
792 PrintStringAt (Column, Row, FormattedNumber);\r
793 if (Number == 10 && (NumericType == DATE_NUMERIC)) {\r
794 PrintChar (RIGHT_NUMERIC_DELIMITER);\r
795 }\r
796\r
797 if (NumericType == REGULAR_NUMERIC) {\r
798 PrintChar (RIGHT_NUMERIC_DELIMITER);\r
799 }\r
800 }\r
801 break;\r
802\r
803 case SCAN_UP:\r
804 case SCAN_DOWN:\r
805 goto EnterCarriageReturn;\r
806\r
807 case SCAN_ESC:\r
808 return EFI_DEVICE_ERROR;\r
809\r
810 default:\r
811 break;\r
812 }\r
813\r
814 break;\r
815\r
816EnterCarriageReturn:\r
817\r
818 case CHAR_CARRIAGE_RETURN:\r
819 //\r
820 // Check to see if the Value is something reasonable against consistency limitations.\r
821 // If not, let's kick the error specified.\r
822 //\r
823 //\r
824 // This gives us visibility to the FileFormTags->NvRamMap to check things\r
825 // ActiveIfr is a global maintained by the menuing code to ensure that we\r
826 // are pointing to the correct formset's file data.\r
827 //\r
828 for (Count = 0; Count < gActiveIfr; Count++) {\r
829 FileFormTags = FileFormTags->NextFile;\r
830 }\r
831\r
832 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
833\r
834 CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);\r
835\r
836 //\r
837 // Data associated with a NULL device (in the fake NV storage)\r
838 //\r
839 if (Tag->StorageWidth == (UINT16) 0) {\r
840 CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);\r
841 }\r
842 //\r
843 // If a late check is required save off the information. This is used when consistency checks\r
844 // are required, but certain values might be bound by an impossible consistency check such as\r
845 // if two questions are bound by consistency checks and each only has two possible choices, there\r
846 // would be no way for a user to switch the values. Thus we require late checking.\r
847 //\r
848 if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {\r
849 CopyMem (&Tag->OldValue, &BackupValue, Tag->StorageWidth);\r
850 } else {\r
851 //\r
852 // In theory, passing the value and the Id are sufficient to determine what needs\r
853 // to be done. The Id is the key to look for the entry needed in the Inconsistency\r
854 // database. That will yields operand and ID data - and since the ID's correspond\r
855 // to the NV storage, we can determine the values for other IDs there.\r
856 //\r
857 if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {\r
858 if (PopUp == 0x0000) {\r
859 SelectionComplete = TRUE;\r
860 break;\r
861 }\r
862\r
863 StringPtr = GetToken (PopUp, MenuOption->Handle);\r
864\r
865 CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);\r
866\r
867 do {\r
868 WaitForKeyStroke (&Key);\r
869\r
870 switch (Key.UnicodeChar) {\r
871\r
872 case CHAR_CARRIAGE_RETURN:\r
873 SelectionComplete = TRUE;\r
874 FreePool (StringPtr);\r
875 break;\r
876\r
877 default:\r
878 break;\r
879 }\r
880 } while (!SelectionComplete);\r
881\r
882 Tag->Value = BackupValue;\r
883 *Value = BackupValue;\r
884\r
885 CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);\r
886\r
887 //\r
888 // Data associated with a NULL device (in the fake NV storage)\r
889 //\r
890 if (Tag->StorageWidth == (UINT16) 0) {\r
891 CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);\r
892 }\r
893\r
894 return EFI_DEVICE_ERROR;\r
895 }\r
896 }\r
897\r
898 return EFI_SUCCESS;\r
899 break;\r
900\r
901 case CHAR_BACKSPACE:\r
902 if (ManualInput) {\r
903 if (Count == 0) {\r
904 break;\r
905 }\r
906 //\r
907 // Remove a character\r
908 //\r
909 Number = PreviousNumber[Count - 1];\r
910 *Value = (UINT16) Number;\r
911 UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);\r
912 Count--;\r
913 Column--;\r
914 PrintAt (Column, Row, (CHAR16 *) L" ");\r
915 }\r
916 break;\r
917\r
918 default:\r
919 if (ManualInput) {\r
920 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
921 UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);\r
922 break;\r
923 }\r
924 //\r
925 // If Count 0-4 is complete, there is no way more is valid\r
926 //\r
927 if (Count > 4) {\r
928 break;\r
929 }\r
930 //\r
931 // Someone typed something valid!\r
932 //\r
933 if (Count != 0) {\r
934 Number = Number * 10 + (Key.UnicodeChar - L'0');\r
935 } else {\r
936 Number = Key.UnicodeChar - L'0';\r
937 }\r
938\r
939 if (Number > Tag->Maximum) {\r
940 UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);\r
941 Number = PreviousNumber[Count];\r
942 break;\r
943 } else {\r
944 UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);\r
945 }\r
946\r
947 Count++;\r
948\r
949 PreviousNumber[Count] = Number;\r
950 *Value = (UINT16) Number;\r
951 Tag->Value = (UINT16) Number;\r
952\r
953 PrintCharAt (Column, Row, Key.UnicodeChar);\r
954 Column++;\r
955 }\r
956 break;\r
957 }\r
958 } while (!SelectionComplete);\r
959 return EFI_SUCCESS;\r
960}\r
961//\r
962// Notice that this is at least needed for the ordered list manipulation.\r
963// Left/Right doesn't make sense for this op-code\r
964//\r
965EFI_STATUS\r
966GetSelectionInputPopUp (\r
967 IN UI_MENU_OPTION *MenuOption,\r
968 IN EFI_TAG *Tag,\r
969 IN UINTN ValueCount,\r
970 OUT UINT16 *Value,\r
971 OUT UINT16 *KeyValue\r
972 )\r
973{\r
974 EFI_INPUT_KEY Key;\r
975 UINTN Index;\r
976 UINTN TempIndex;\r
977 CHAR16 *StringPtr;\r
978 CHAR16 *TempStringPtr;\r
979 UINT16 Token;\r
980 UINTN Index2;\r
981 UINTN TopOptionIndex;\r
982 UINTN HighlightPosition;\r
983 UINTN Start;\r
984 UINTN End;\r
985 UINTN Top;\r
986 UINTN Bottom;\r
987 UINT16 TempValue;\r
988 UINTN Count;\r
989 UINTN PopUpMenuLines;\r
990 UINTN MenuLinesInView;\r
991 UINTN PopUpWidth;\r
992 CHAR16 Character;\r
993 BOOLEAN FirstOptionFoundFlag;\r
994 INT32 SavedAttribute;\r
995 EFI_TAG TagBackup;\r
996 UINT8 *ValueArray;\r
997 UINT8 *ValueArrayBackup;\r
998 UINT8 ValueBackup;\r
999 BOOLEAN Initialized;\r
1000 BOOLEAN KeyInitialized;\r
1001 BOOLEAN ShowDownArrow;\r
1002 BOOLEAN ShowUpArrow;\r
1003 UINTN DimensionsWidth;\r
1004\r
1005 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
1006\r
1007 TempValue = 0;\r
1008 TempIndex = 0;\r
1009 ValueArray = (UINT8 *) Value;\r
1010 ValueArrayBackup = NULL;\r
1011 Initialized = FALSE;\r
1012 KeyInitialized = FALSE;\r
1013 ShowDownArrow = FALSE;\r
1014 ShowUpArrow = FALSE;\r
1015\r
1016 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1017 ValueArrayBackup = AllocateZeroPool (Tag->StorageWidth);\r
1018 ASSERT (ValueArrayBackup != NULL);\r
1019 CopyMem (ValueArrayBackup, ValueArray, ValueCount);\r
1020 TempValue = *(UINT8 *) (ValueArray);\r
1021 if (ValueArray[0] != 0x00) {\r
1022 Initialized = TRUE;\r
1023 }\r
1024\r
1025 for (Index = 0; ValueArray[Index] != 0x00; Index++)\r
1026 ;\r
1027 ValueCount = Index;\r
1028 } else {\r
1029 TempValue = *Value;\r
1030 }\r
1031\r
1032 Count = 0;\r
1033 PopUpWidth = 0;\r
1034\r
1035 FirstOptionFoundFlag = FALSE;\r
1036\r
1037 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
1038 ASSERT (StringPtr);\r
1039\r
1040 //\r
1041 // Initialization for "One of" pop-up menu\r
1042 //\r
1043 //\r
1044 // Get the number of one of options present and its size\r
1045 //\r
1046 for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {\r
1047 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1048 !MenuOption->Tags[Index].Suppress) {\r
1049 if (!FirstOptionFoundFlag) {\r
1050 FirstOptionFoundFlag = TRUE;\r
1051 }\r
1052\r
1053 Count++;\r
1054 Token = MenuOption->Tags[Index].Text;\r
1055\r
1056 //\r
1057 // If this is an ordered list that is initialized\r
1058 //\r
1059 if (Initialized) {\r
1060 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1061 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP;\r
1062 ValueBackup++\r
1063 ) {\r
1064 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1065 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1066 break;\r
1067 }\r
1068 }\r
1069 } else {\r
1070 StringPtr = GetToken (Token, MenuOption->Handle);\r
1071 }\r
1072\r
1073 if (StrLen (StringPtr) > PopUpWidth) {\r
1074 PopUpWidth = StrLen (StringPtr);\r
1075 }\r
1076\r
1077 FreePool (StringPtr);\r
1078 }\r
1079 }\r
1080 //\r
1081 // Perform popup menu initialization.\r
1082 //\r
1083 PopUpMenuLines = Count;\r
1084 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
1085\r
1086 SavedAttribute = gST->ConOut->Mode->Attribute;\r
1087 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1088\r
1089 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
1090 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
1091 }\r
1092\r
1093 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;\r
1094 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
1095 Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
1096 Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT;\r
1097\r
1098 MenuLinesInView = Bottom - Top - 1;\r
1099 if (MenuLinesInView >= PopUpMenuLines) {\r
1100 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
1101 Bottom = Top + PopUpMenuLines + 1;\r
1102 } else {\r
1103 TempValue = MenuOption->Tags[MenuOption->TagIndex + 1].Value;\r
1104 ShowDownArrow = TRUE;\r
1105 }\r
1106\r
1107 TopOptionIndex = 1;\r
1108 HighlightPosition = 0;\r
1109 do {\r
1110 if (Initialized) {\r
1111 for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) {\r
1112 //\r
1113 // Set the value for the item we are looking for\r
1114 //\r
1115 Count = ValueArrayBackup[Index2];\r
1116\r
1117 //\r
1118 // If we hit the end of the Array, we are complete\r
1119 //\r
1120 if (Count == 0) {\r
1121 break;\r
1122 }\r
1123\r
1124 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1125 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1126 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1127 ValueBackup++\r
1128 ) {\r
1129 //\r
1130 // We just found what we are looking for\r
1131 //\r
1132 if (MenuOption->Tags[ValueBackup].Value == Count) {\r
1133 //\r
1134 // As long as the two indexes aren't the same, we have\r
1135 // two different op-codes we need to swap internally\r
1136 //\r
1137 if (Index != ValueBackup) {\r
1138 //\r
1139 // Backup destination tag, then copy source to destination, then copy backup to source location\r
1140 //\r
1141 CopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1142 CopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG));\r
1143 CopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG));\r
1144 } else {\r
1145 //\r
1146 // If the indexes are the same, then the op-code is where he belongs\r
1147 //\r
1148 }\r
1149 }\r
1150 }\r
1151 } else {\r
1152 //\r
1153 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2\r
1154 //\r
1155 Index2--;\r
1156 }\r
1157 }\r
1158 }\r
1159 //\r
1160 // Clear that portion of the screen\r
1161 //\r
1162 ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);\r
1163\r
1164 //\r
1165 // Draw "One of" pop-up menu\r
1166 //\r
1167 Character = (CHAR16) BOXDRAW_DOWN_RIGHT;\r
1168 PrintCharAt (Start, Top, Character);\r
1169 for (Index = Start; Index + 2 < End; Index++) {\r
1170 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1171 Character = (CHAR16) GEOMETRICSHAPE_UP_TRIANGLE;\r
1172 } else {\r
1173 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1174 }\r
1175\r
1176 PrintChar (Character);\r
1177 }\r
1178\r
1179 Character = (CHAR16) BOXDRAW_DOWN_LEFT;\r
1180 PrintChar (Character);\r
1181 Character = (CHAR16) BOXDRAW_VERTICAL;\r
1182 for (Index = Top + 1; Index < Bottom; Index++) {\r
1183 PrintCharAt (Start, Index, Character);\r
1184 PrintCharAt (End - 1, Index, Character);\r
1185 }\r
1186 //\r
1187 // Display the One of options\r
1188 //\r
1189 Index2 = Top + 1;\r
1190 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1191 (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom);\r
1192 Index++\r
1193 ) {\r
1194 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1195 Token = MenuOption->Tags[Index].Text;\r
1196 if (Initialized) {\r
1197 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1198 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1199 ValueBackup++\r
1200 ) {\r
1201 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1202 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1203 break;\r
1204 }\r
1205 }\r
1206 } else {\r
1207 ValueBackup = (UINT8) Index;\r
1208 StringPtr = GetToken (Token, MenuOption->Handle);\r
1209 }\r
1210 //\r
1211 // If the string occupies multiple lines, truncate it to fit in one line,\r
1212 // and append a "..." for indication.\r
1213 //\r
1214 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
1215 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
1216 ASSERT (TempStringPtr != NULL);\r
1217 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
1218 FreePool (StringPtr);\r
1219 StringPtr = TempStringPtr;\r
1220 StrCat (StringPtr, (CHAR16 *) L"...");\r
1221 }\r
1222 //\r
1223 // Code to display the text should go here. Follwed by the [*]\r
1224 //\r
1225 if (MenuOption->Tags[ValueBackup].Suppress == TRUE) {\r
1226 //\r
1227 // Don't show the one, so decrease the Index2 for balance\r
1228 //\r
1229 Index2--;\r
1230 } else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) {\r
1231 //\r
1232 // Gray Out the one\r
1233 //\r
1234 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND);\r
1235 PrintStringAt (Start + 2, Index2, StringPtr);\r
1236 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1237 } else if (MenuOption->Tags[ValueBackup].Value == TempValue) {\r
1238 //\r
1239 // Highlight the selected one\r
1240 //\r
1241 gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);\r
1242 PrintStringAt (Start + 2, Index2, StringPtr);\r
1243 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1244 HighlightPosition = Index2;\r
1245 } else {\r
1246 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1247 PrintStringAt (Start + 2, Index2, StringPtr);\r
1248 }\r
1249\r
1250 FreePool (StringPtr);\r
1251 Index2 = Index2 + 1;\r
1252 }\r
1253 }\r
1254\r
1255 Character = (CHAR16) BOXDRAW_UP_RIGHT;\r
1256 PrintCharAt (Start, Bottom, Character);\r
1257 for (Index = Start; Index + 2 < End; Index++) {\r
1258 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1259 Character = (CHAR16) GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1260 } else {\r
1261 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1262 }\r
1263\r
1264 PrintChar (Character);\r
1265 }\r
1266\r
1267 Character = (CHAR16) BOXDRAW_UP_LEFT;\r
1268 PrintChar (Character);\r
1269 //\r
1270 // Get User selection and change TempValue if necessary\r
1271 //\r
1272 //\r
1273 // Stop: One of pop-up menu\r
1274 //\r
1275 Key.UnicodeChar = CHAR_NULL;\r
1276 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1277 Key.ScanCode = gDirection;\r
1278 gDirection = 0;\r
1279 goto TheKey;\r
1280 }\r
1281\r
1282 if (!KeyInitialized) {\r
1283 if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) {\r
1284 *KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key;\r
1285 } else {\r
1286 *KeyValue = MenuOption->ThisTag->Key;\r
1287 }\r
1288\r
1289 KeyInitialized = TRUE;\r
1290 }\r
1291\r
1292 WaitForKeyStroke (&Key);\r
1293\r
1294TheKey:\r
1295 switch (Key.UnicodeChar) {\r
1296 case '+':\r
1297 case '-':\r
1298 //\r
1299 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1300 // to create an ordered list of items\r
1301 //\r
1302 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1303 if (Key.UnicodeChar == '+') {\r
1304 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1305 //\r
1306 // Highlight reaches the top of the popup window, scroll one menu item.\r
1307 //\r
1308 TopOptionIndex--;\r
1309 ShowDownArrow = TRUE;\r
1310 }\r
1311\r
1312 if (TopOptionIndex == 1) {\r
1313 ShowUpArrow = FALSE;\r
1314 }\r
1315 } else {\r
1316 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1317 //\r
1318 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1319 //\r
1320 TopOptionIndex++;\r
1321 ShowUpArrow = TRUE;\r
1322 }\r
1323\r
1324 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1325 ShowDownArrow = FALSE;\r
1326 }\r
1327 }\r
1328\r
1329 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1330 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1331 Index++\r
1332 ) {\r
1333 if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1334 continue;\r
1335 }\r
1336\r
1337 if (Key.UnicodeChar == '+') {\r
1338 TempIndex = Index - 1;\r
1339 } else {\r
1340 TempIndex = Index + 1;\r
1341 }\r
1342 //\r
1343 // Is this the current tag we are on?\r
1344 //\r
1345 if (MenuOption->Tags[Index].Value == TempValue) {\r
1346 //\r
1347 // Is this prior tag a valid choice? If not, bail out\r
1348 //\r
1349 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1350 //\r
1351 // Copy the destination tag to the local variable\r
1352 //\r
1353 CopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG));\r
1354 //\r
1355 // Copy the current tag to the tag location before us\r
1356 //\r
1357 CopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1358 //\r
1359 // Copy the backed up tag to the current location\r
1360 //\r
1361 CopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG));\r
1362\r
1363 //\r
1364 // Adjust the array of values\r
1365 //\r
1366 for (Index = 0; Index < ValueCount; Index++) {\r
1367 if (ValueArrayBackup[Index] == (UINT8) TempValue) {\r
1368 if (Key.UnicodeChar == '+') {\r
1369 if (Index == 0) {\r
1370 //\r
1371 // It is the top of the array already\r
1372 //\r
1373 break;\r
1374 }\r
1375\r
1376 TempIndex = Index - 1;\r
1377 } else {\r
1378 if ((Index + 1) == ValueCount) {\r
1379 //\r
1380 // It is the bottom of the array already\r
1381 //\r
1382 break;\r
1383 }\r
1384\r
1385 TempIndex = Index + 1;\r
1386 }\r
1387\r
1388 ValueBackup = ValueArrayBackup[TempIndex];\r
1389 ValueArrayBackup[TempIndex] = ValueArrayBackup[Index];\r
1390 ValueArrayBackup[Index] = ValueBackup;\r
1391 Initialized = TRUE;\r
1392 break;\r
1393 }\r
1394 }\r
1395 break;\r
1396 } else {\r
1397 break;\r
1398 }\r
1399 }\r
1400 }\r
1401 }\r
1402 break;\r
1403\r
1404 case CHAR_NULL:\r
1405 switch (Key.ScanCode) {\r
1406 case SCAN_UP:\r
1407 case SCAN_DOWN:\r
1408 if (Key.ScanCode == SCAN_UP) {\r
1409 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1410 //\r
1411 // Highlight reaches the top of the popup window, scroll one menu item.\r
1412 //\r
1413 TopOptionIndex--;\r
1414 ShowDownArrow = TRUE;\r
1415 }\r
1416\r
1417 if (TopOptionIndex == 1) {\r
1418 ShowUpArrow = FALSE;\r
1419 }\r
1420 } else {\r
1421 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1422 //\r
1423 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1424 //\r
1425 TopOptionIndex++;\r
1426 ShowUpArrow = TRUE;\r
1427 }\r
1428\r
1429 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1430 ShowDownArrow = FALSE;\r
1431 }\r
1432 }\r
1433\r
1434 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1435 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1436 Index++\r
1437 ) {\r
1438 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1439 if (Initialized) {\r
1440 for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++)\r
1441 ;\r
1442\r
1443 //\r
1444 // Did we hit the end of the array? Either get the first TempValue or the next one\r
1445 //\r
1446 if (Key.ScanCode == SCAN_UP) {\r
1447 if (Index == 0) {\r
1448 TempValue = ValueArrayBackup[0];\r
1449 } else {\r
1450 TempValue = ValueArrayBackup[Index - 1];\r
1451 }\r
1452 } else {\r
1453 if ((Index + 1) == ValueCount) {\r
1454 TempValue = ValueArrayBackup[Index];\r
1455 } else {\r
1456 TempValue = ValueArrayBackup[Index + 1];\r
1457 }\r
1458 }\r
1459 break;\r
1460 } else {\r
1461 if (Key.ScanCode == SCAN_UP) {\r
1462 TempIndex = Index - 1;\r
1463\r
1464 //\r
1465 // Keep going until meets meaningful tag.\r
1466 //\r
1467 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1468 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1469 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1470 ||\r
1471 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1472 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1473 TempIndex--;\r
1474 }\r
1475 } else {\r
1476 TempIndex = Index + 1;\r
1477\r
1478 //\r
1479 // Keep going until meets meaningful tag.\r
1480 //\r
1481 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1482 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1483 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1484 ||\r
1485 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1486 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1487 TempIndex++;\r
1488 }\r
1489 }\r
1490 //\r
1491 // The option value is the same as what is stored in NV store. This is where we take action\r
1492 //\r
1493 if (MenuOption->Tags[Index].Value == TempValue) {\r
1494 //\r
1495 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option\r
1496 //\r
1497 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1498 TempValue = MenuOption->Tags[TempIndex].Value;\r
1499 *KeyValue = MenuOption->Tags[TempIndex].Key;\r
1500 } else {\r
1501 TempValue = MenuOption->Tags[Index].Value;\r
1502 *KeyValue = MenuOption->Tags[Index].Key;\r
1503 }\r
1504 break;\r
1505 }\r
1506 }\r
1507 }\r
1508 }\r
1509 break;\r
1510\r
1511 case SCAN_ESC:\r
1512 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1513 if (ValueArrayBackup != NULL) {\r
1514 FreePool (ValueArrayBackup);\r
1515 }\r
1516\r
1517 return EFI_DEVICE_ERROR;\r
1518\r
1519 default:\r
1520 break;\r
1521 }\r
1522\r
1523 break;\r
1524\r
1525 case CHAR_CARRIAGE_RETURN:\r
1526 //\r
1527 // return the current selection\r
1528 //\r
1529 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1530 CopyMem (ValueArray, ValueArrayBackup, ValueCount);\r
1531 FreePool (ValueArrayBackup);\r
1532 } else {\r
1533 *Value = TempValue;\r
1534 }\r
1535\r
1536 goto Done;\r
1537\r
1538 default:\r
1539 break;\r
1540 }\r
1541 } while (1);\r
1542\r
1543Done:\r
1544 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1545 return EFI_SUCCESS;\r
1546}\r
1547\r
1548EFI_STATUS\r
1549WaitForKeyStroke (\r
1550 OUT EFI_INPUT_KEY *Key\r
1551 )\r
1552{\r
1553 EFI_STATUS Status;\r
1554\r
1555 do {\r
1556 UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
1557 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
1558 } while (EFI_ERROR(Status));\r
1559\r
1560 return Status;\r
1561}\r