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