]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/SetupBrowserDxe/InputHandler.c
Fix a memory leak issue.
[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
ebc1ca5a 293 if (Packet != NULL && Packet->String != NULL) {\r
103b6520 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
ebc1ca5a 406 if (Packet == NULL || Packet->String == NULL) {\r
103b6520 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
d6b50e78 414 FreePool (Packet->String);\r
103b6520 415 FreePool (Packet);\r
416 }\r
417\r
418 StringPtr[0] = CHAR_NULL;\r
419 do {\r
420 Status = WaitForKeyStroke (&Key);\r
421\r
422 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
423 Status = EFI_NOT_READY;\r
424 goto Done;\r
425 }\r
426 } while (1);\r
427 } else {\r
428 Status = EFI_NOT_READY;\r
429 goto Done;\r
430 }\r
431 } else {\r
432 //\r
433 // User typed a string in and it wasn't valid somehow from the callback\r
434 // For instance, callback may have said that some invalid characters were contained in the string\r
435 //\r
436 if (Status == EFI_NOT_READY) {\r
437 goto Error;\r
438 }\r
439\r
440 if (PromptForPassword && EFI_ERROR (Status)) {\r
441 Status = EFI_DEVICE_ERROR;\r
442 goto Done;\r
443 }\r
444 }\r
445 }\r
446\r
447 if (Confirmation) {\r
448 //\r
449 // Compare tempstring and tempstring2, if the same, return with StringPtr success\r
450 // Otherwise, kick and error box, and return an error\r
451 //\r
452 if (StrCmp (TempString, TempString2) == 0) {\r
453 Status = EFI_SUCCESS;\r
454 goto Done;\r
455 } else {\r
456 WidthOfString = GetStringWidth (gConfirmError);\r
a1e3528b 457 ScreenSize = MAX (WidthOfString, GetStringWidth (gPressEnter)) / 2;\r
103b6520 458 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);\r
459 StringPtr[0] = CHAR_NULL;\r
460 do {\r
461 Status = WaitForKeyStroke (&Key);\r
462 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
463 Status = EFI_DEVICE_ERROR;\r
464 goto Done;\r
465 }\r
466 } while (1);\r
467 }\r
468 }\r
469\r
470 if (PromptForPassword) {\r
471 //\r
472 // I was asked for a password, return it back in StringPtr\r
473 //\r
474 Status = EFI_SUCCESS;\r
475 goto Done;\r
476 } else {\r
477 //\r
478 // If the two passwords were not the same kick an error popup\r
479 //\r
480 Confirmation = TRUE;\r
481 ConfirmationComplete = TRUE;\r
482 break;\r
483 }\r
484\r
485 case CHAR_BACKSPACE:\r
486 if (StringPtr[0] != CHAR_NULL) {\r
487 if (!Confirmation) {\r
488 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
489 TempString[Index] = StringPtr[Index];\r
490 }\r
491 //\r
492 // Effectively truncate string by 1 character\r
493 //\r
494 TempString[Index - 1] = CHAR_NULL;\r
495 StrCpy (StringPtr, TempString);\r
496 } else {\r
497 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
498 TempString2[Index] = StringPtr[Index];\r
499 }\r
500 //\r
501 // Effectively truncate string by 1 character\r
502 //\r
503 TempString2[Index - 1] = CHAR_NULL;\r
504 StrCpy (StringPtr, TempString2);\r
505 }\r
506\r
507 ConfirmationComplete = FALSE;\r
508 } else {\r
509 ConfirmationComplete = FALSE;\r
510 }\r
511\r
512 //\r
513 // Must be a character we are interested in!\r
514 //\r
515 default:\r
516 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
ebc1ca5a 517 StringPtr[0] = Key.UnicodeChar;\r
518 StringPtr[1] = CHAR_NULL;\r
103b6520 519 if (!Confirmation) {\r
ebc1ca5a 520 TempString[0] = Key.UnicodeChar;\r
521 TempString[1] = CHAR_NULL;\r
103b6520 522 } else {\r
ebc1ca5a 523 TempString2[0] = Key.UnicodeChar;\r
524 TempString2[1] = CHAR_NULL;\r
103b6520 525 ConfirmationComplete = FALSE;\r
526 }\r
527 } else if ((GetStringWidth (StringPtr) / 2 <= (UINTN) (MenuOption->ThisTag->Maximum - 1) / 2) &&\r
528 (Key.UnicodeChar != CHAR_BACKSPACE)\r
529 ) {\r
530 KeyPad[0] = Key.UnicodeChar;\r
531 KeyPad[1] = CHAR_NULL;\r
532 if (!Confirmation) {\r
533 StrCat (StringPtr, KeyPad);\r
534 StrCat (TempString, KeyPad);\r
535 } else {\r
536 StrCat (StringPtr, KeyPad);\r
537 StrCat (TempString2, KeyPad);\r
538 }\r
539 }\r
540\r
541 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
542 for (Index = 1; Index < ScreenSize; Index++) {\r
543 PrintCharAt (Start + Index, Top + 3, L' ');\r
544 }\r
545\r
546 gST->ConOut->SetCursorPosition (\r
547 gST->ConOut,\r
548 (DimensionsWidth - GetStringWidth (StringPtr) / 2) / 2 + gScreenDimensions.LeftColumn,\r
549 Top + 3\r
550 );\r
551 for (Index = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++) {\r
552 PrintChar (L'*');\r
553 }\r
554\r
555 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
556 break;\r
557 }\r
558 //\r
559 // end switch\r
560 //\r
561 } while (!ConfirmationComplete);\r
562\r
563 } while (1);\r
564\r
565Done:\r
566 FreePool (TempString);\r
567 FreePool (TempString2);\r
568 return Status;\r
569}\r
570\r
571VOID\r
572EncodePassword (\r
573 IN CHAR16 *Password,\r
574 IN UINT8 MaxSize\r
575 )\r
576{\r
577 UINTN Index;\r
578 UINTN Loop;\r
579 CHAR16 *Buffer;\r
580 CHAR16 *Key;\r
581\r
582 Key = (CHAR16 *) L"MAR10648567";\r
583 Buffer = AllocateZeroPool (MaxSize);\r
584\r
585 ASSERT (Buffer);\r
586\r
587 for (Index = 0; Key[Index] != 0; Index++) {\r
588 for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) {\r
589 Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]);\r
590 }\r
591 }\r
592\r
593 CopyMem (Password, Buffer, MaxSize);\r
594\r
595 FreePool (Buffer);\r
596 return ;\r
597}\r
598\r
599EFI_STATUS\r
600GetNumericInput (\r
601 IN UI_MENU_OPTION *MenuOption,\r
602 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
603 IN BOOLEAN ManualInput,\r
604 IN EFI_TAG *Tag,\r
605 IN UINTN NumericType,\r
606 OUT UINT16 *Value\r
607 )\r
608/*++\r
609\r
610Routine Description:\r
611\r
612 This routine reads a numeric value from the user input.\r
613\r
614Arguments:\r
615\r
616 MenuOption - Pointer to the current input menu.\r
617\r
618 FileFormTagsHead - Pointer to the root of formset.\r
619\r
620 ManualInput - If the input is manual or not.\r
621\r
622 Tag - Pointer to all the attributes and values associated with a tag.\r
623\r
624 Value - Pointer to the numeric value that is going to be read.\r
625\r
626Returns:\r
627\r
628 EFI_SUCCESS - If numerical input is read successfully\r
629 EFI_DEVICE_ERROR - If operation fails\r
630\r
631--*/\r
632{\r
633 EFI_INPUT_KEY Key;\r
634 BOOLEAN SelectionComplete;\r
635 UINTN Column;\r
636 UINTN Row;\r
637 CHAR16 FormattedNumber[6];\r
638 UINTN PreviousNumber[6];\r
639 INTN Number;\r
640 UINTN Count;\r
641 UINT16 BackupValue;\r
642 STRING_REF PopUp;\r
643 CHAR16 NullCharacter;\r
644 CHAR16 *StringPtr;\r
645 EFI_FILE_FORM_TAGS *FileFormTags;\r
646 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
647 UINTN Loop;\r
648\r
649 NullCharacter = CHAR_NULL;\r
650 StringPtr = NULL;\r
651 Column = MenuOption->OptCol;\r
652 Row = MenuOption->Row;\r
653 Number = 0;\r
654 PreviousNumber[0] = 0;\r
655 Count = 0;\r
656 SelectionComplete = FALSE;\r
657 BackupValue = Tag->Value;\r
658 FileFormTags = FileFormTagsHead;\r
659\r
660 if (ManualInput) {\r
661 PrintAt (Column, Row, (CHAR16 *) L"[ ]");\r
662 Column++;\r
663 if (Tag->Operand != EFI_IFR_TIME_OP) {\r
664 *Value = BackupValue;\r
665 }\r
666 }\r
667 //\r
668 // First time we enter this handler, we need to check to see if\r
669 // we were passed an increment or decrement directive\r
670 //\r
671 do {\r
672 Key.UnicodeChar = CHAR_NULL;\r
673 if (gDirection != 0) {\r
674 Key.ScanCode = gDirection;\r
675 gDirection = 0;\r
676 goto TheKey2;\r
677 }\r
678\r
679 WaitForKeyStroke (&Key);\r
680\r
681TheKey2:\r
682 switch (Key.UnicodeChar) {\r
683 case '+':\r
684 case '-':\r
685 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
686 Key.UnicodeChar = CHAR_NULL;\r
687 if (Key.UnicodeChar == '+') {\r
688 Key.ScanCode = SCAN_RIGHT;\r
689 } else {\r
690 Key.ScanCode = SCAN_LEFT;\r
691 }\r
692\r
693 goto TheKey2;\r
694 }\r
695 break;\r
696\r
697 case CHAR_NULL:\r
698 switch (Key.ScanCode) {\r
699 case SCAN_LEFT:\r
700 case SCAN_RIGHT:\r
701 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
702 //\r
703 // By setting this value, we will return back to the caller.\r
704 // We need to do this since an auto-refresh will destroy the adjustment\r
705 // based on what the real-time-clock is showing. So we always commit\r
706 // upon changing the value.\r
707 //\r
708 gDirection = SCAN_DOWN;\r
709 }\r
710\r
711 if (!ManualInput) {\r
712 Tag->Value = *Value;\r
713 if (Key.ScanCode == SCAN_LEFT) {\r
714 Number = *Value - Tag->Step;\r
715 if (Number < Tag->Minimum) {\r
716 Number = Tag->Minimum;\r
717 }\r
718 } else if (Key.ScanCode == SCAN_RIGHT) {\r
719 Number = *Value + Tag->Step;\r
720 if (Number > Tag->Maximum) {\r
721 Number = Tag->Maximum;\r
722 }\r
723 }\r
724\r
725 Tag->Value = (UINT16) Number;\r
726 *Value = (UINT16) Number;\r
727 UnicodeValueToString (\r
728 FormattedNumber,\r
729 FALSE,\r
730 (UINTN) Number,\r
731 (sizeof (FormattedNumber) / sizeof (FormattedNumber[0]))\r
732 );\r
733 Number = (UINT16) GetStringWidth (FormattedNumber);\r
734\r
735 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT | FIELD_BACKGROUND);\r
736 if ((Tag->Operand == EFI_IFR_DATE_OP) || (Tag->Operand == EFI_IFR_TIME_OP)) {\r
737 for (Loop = 0; Loop < (UINTN) ((Number >= 8) ? 4 : 2); Loop++) {\r
738 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");\r
739 }\r
740 } else {\r
741 for (Loop = 0; Loop < gOptionBlockWidth; Loop++) {\r
742 PrintAt (MenuOption->OptCol + Loop, MenuOption->Row, (CHAR16 *) L" ");\r
743 }\r
744 }\r
745\r
746 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_HIGHLIGHT | FIELD_BACKGROUND_HIGHLIGHT);\r
747\r
748 if ((MenuOption->Col + gPromptBlockWidth + 1) == MenuOption->OptCol) {\r
749 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
750 Column = MenuOption->OptCol + 1;\r
751 }\r
752 //\r
753 // If Number looks like "3", convert it to "03/"\r
754 //\r
755 if (Number == 4 && (NumericType == DATE_NUMERIC)) {\r
756 FormattedNumber[3] = FormattedNumber[1];\r
757 FormattedNumber[2] = DATE_SEPARATOR;\r
758 FormattedNumber[1] = FormattedNumber[0];\r
759 FormattedNumber[0] = L'0';\r
760 Number = 8;\r
761 }\r
762 //\r
763 // If Number looks like "13", convert it to "13/"\r
764 //\r
765 if (Number == 6 && (NumericType == DATE_NUMERIC)) {\r
766 FormattedNumber[3] = FormattedNumber[2];\r
767 FormattedNumber[2] = DATE_SEPARATOR;\r
768 Number = 8;\r
769 }\r
770\r
771 if (Number == 4 &&\r
772 (NumericType == TIME_NUMERIC) &&\r
773 (MenuOption->Col + gPromptBlockWidth + 8) != MenuOption->OptCol\r
774 ) {\r
775 FormattedNumber[3] = FormattedNumber[1];\r
776 FormattedNumber[2] = TIME_SEPARATOR;\r
777 FormattedNumber[1] = FormattedNumber[0];\r
778 FormattedNumber[0] = L'0';\r
779 Number = 8;\r
780 }\r
781\r
782 if (Number == 4 &&\r
783 (NumericType == TIME_NUMERIC) &&\r
784 (MenuOption->Col + gPromptBlockWidth + 8) == MenuOption->OptCol\r
785 ) {\r
786 FormattedNumber[3] = FormattedNumber[1];\r
787 FormattedNumber[2] = RIGHT_NUMERIC_DELIMITER;\r
788 FormattedNumber[1] = FormattedNumber[0];\r
789 FormattedNumber[0] = L'0';\r
790 Number = 8;\r
791 }\r
792\r
793 PrintStringAt (Column, Row, FormattedNumber);\r
794 if (Number == 10 && (NumericType == DATE_NUMERIC)) {\r
795 PrintChar (RIGHT_NUMERIC_DELIMITER);\r
796 }\r
797\r
798 if (NumericType == REGULAR_NUMERIC) {\r
799 PrintChar (RIGHT_NUMERIC_DELIMITER);\r
800 }\r
801 }\r
802 break;\r
803\r
804 case SCAN_UP:\r
805 case SCAN_DOWN:\r
806 goto EnterCarriageReturn;\r
807\r
808 case SCAN_ESC:\r
809 return EFI_DEVICE_ERROR;\r
810\r
811 default:\r
812 break;\r
813 }\r
814\r
815 break;\r
816\r
817EnterCarriageReturn:\r
818\r
819 case CHAR_CARRIAGE_RETURN:\r
820 //\r
821 // Check to see if the Value is something reasonable against consistency limitations.\r
822 // If not, let's kick the error specified.\r
823 //\r
824 //\r
825 // This gives us visibility to the FileFormTags->NvRamMap to check things\r
826 // ActiveIfr is a global maintained by the menuing code to ensure that we\r
827 // are pointing to the correct formset's file data.\r
828 //\r
829 for (Count = 0; Count < gActiveIfr; Count++) {\r
830 FileFormTags = FileFormTags->NextFile;\r
831 }\r
832\r
833 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
834\r
835 CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);\r
836\r
837 //\r
838 // Data associated with a NULL device (in the fake NV storage)\r
839 //\r
840 if (Tag->StorageWidth == (UINT16) 0) {\r
841 CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);\r
842 }\r
843 //\r
844 // If a late check is required save off the information. This is used when consistency checks\r
845 // are required, but certain values might be bound by an impossible consistency check such as\r
846 // if two questions are bound by consistency checks and each only has two possible choices, there\r
847 // would be no way for a user to switch the values. Thus we require late checking.\r
848 //\r
849 if (Tag->Flags & EFI_IFR_FLAG_LATE_CHECK) {\r
850 CopyMem (&Tag->OldValue, &BackupValue, Tag->StorageWidth);\r
851 } else {\r
852 //\r
853 // In theory, passing the value and the Id are sufficient to determine what needs\r
854 // to be done. The Id is the key to look for the entry needed in the Inconsistency\r
855 // database. That will yields operand and ID data - and since the ID's correspond\r
856 // to the NV storage, we can determine the values for other IDs there.\r
857 //\r
858 if (ValueIsNotValid (TRUE, 0, Tag, FileFormTags, &PopUp)) {\r
859 if (PopUp == 0x0000) {\r
860 SelectionComplete = TRUE;\r
861 break;\r
862 }\r
863\r
864 StringPtr = GetToken (PopUp, MenuOption->Handle);\r
865\r
866 CreatePopUp (GetStringWidth (StringPtr) / 2, 3, &NullCharacter, StringPtr, &NullCharacter);\r
867\r
868 do {\r
869 WaitForKeyStroke (&Key);\r
870\r
871 switch (Key.UnicodeChar) {\r
872\r
873 case CHAR_CARRIAGE_RETURN:\r
874 SelectionComplete = TRUE;\r
875 FreePool (StringPtr);\r
876 break;\r
877\r
878 default:\r
879 break;\r
880 }\r
881 } while (!SelectionComplete);\r
882\r
883 Tag->Value = BackupValue;\r
884 *Value = BackupValue;\r
885\r
886 CopyMem (&VariableDefinition->NvRamMap[Tag->StorageStart], &Tag->Value, Tag->StorageWidth);\r
887\r
888 //\r
889 // Data associated with a NULL device (in the fake NV storage)\r
890 //\r
891 if (Tag->StorageWidth == (UINT16) 0) {\r
892 CopyMem (&VariableDefinition->FakeNvRamMap[Tag->StorageStart], &Tag->Value, 2);\r
893 }\r
894\r
895 return EFI_DEVICE_ERROR;\r
896 }\r
897 }\r
898\r
899 return EFI_SUCCESS;\r
900 break;\r
901\r
902 case CHAR_BACKSPACE:\r
903 if (ManualInput) {\r
904 if (Count == 0) {\r
905 break;\r
906 }\r
907 //\r
908 // Remove a character\r
909 //\r
910 Number = PreviousNumber[Count - 1];\r
911 *Value = (UINT16) Number;\r
912 UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);\r
913 Count--;\r
914 Column--;\r
915 PrintAt (Column, Row, (CHAR16 *) L" ");\r
916 }\r
917 break;\r
918\r
919 default:\r
920 if (ManualInput) {\r
921 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
922 UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);\r
923 break;\r
924 }\r
925 //\r
926 // If Count 0-4 is complete, there is no way more is valid\r
927 //\r
928 if (Count > 4) {\r
929 break;\r
930 }\r
931 //\r
932 // Someone typed something valid!\r
933 //\r
934 if (Count != 0) {\r
935 Number = Number * 10 + (Key.UnicodeChar - L'0');\r
936 } else {\r
937 Number = Key.UnicodeChar - L'0';\r
938 }\r
939\r
940 if (Number > Tag->Maximum) {\r
941 UpdateStatusBar (INPUT_ERROR, Tag->Flags, TRUE);\r
942 Number = PreviousNumber[Count];\r
943 break;\r
944 } else {\r
945 UpdateStatusBar (INPUT_ERROR, Tag->Flags, FALSE);\r
946 }\r
947\r
948 Count++;\r
949\r
950 PreviousNumber[Count] = Number;\r
951 *Value = (UINT16) Number;\r
952 Tag->Value = (UINT16) Number;\r
953\r
954 PrintCharAt (Column, Row, Key.UnicodeChar);\r
955 Column++;\r
956 }\r
957 break;\r
958 }\r
959 } while (!SelectionComplete);\r
960 return EFI_SUCCESS;\r
961}\r
962//\r
963// Notice that this is at least needed for the ordered list manipulation.\r
964// Left/Right doesn't make sense for this op-code\r
965//\r
966EFI_STATUS\r
967GetSelectionInputPopUp (\r
968 IN UI_MENU_OPTION *MenuOption,\r
969 IN EFI_TAG *Tag,\r
970 IN UINTN ValueCount,\r
971 OUT UINT16 *Value,\r
972 OUT UINT16 *KeyValue\r
973 )\r
974{\r
975 EFI_INPUT_KEY Key;\r
976 UINTN Index;\r
977 UINTN TempIndex;\r
978 CHAR16 *StringPtr;\r
979 CHAR16 *TempStringPtr;\r
980 UINT16 Token;\r
981 UINTN Index2;\r
982 UINTN TopOptionIndex;\r
983 UINTN HighlightPosition;\r
984 UINTN Start;\r
985 UINTN End;\r
986 UINTN Top;\r
987 UINTN Bottom;\r
988 UINT16 TempValue;\r
989 UINTN Count;\r
990 UINTN PopUpMenuLines;\r
991 UINTN MenuLinesInView;\r
992 UINTN PopUpWidth;\r
993 CHAR16 Character;\r
994 BOOLEAN FirstOptionFoundFlag;\r
995 INT32 SavedAttribute;\r
996 EFI_TAG TagBackup;\r
997 UINT8 *ValueArray;\r
998 UINT8 *ValueArrayBackup;\r
999 UINT8 ValueBackup;\r
1000 BOOLEAN Initialized;\r
1001 BOOLEAN KeyInitialized;\r
1002 BOOLEAN ShowDownArrow;\r
1003 BOOLEAN ShowUpArrow;\r
1004 UINTN DimensionsWidth;\r
1005\r
1006 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
1007\r
1008 TempValue = 0;\r
1009 TempIndex = 0;\r
1010 ValueArray = (UINT8 *) Value;\r
1011 ValueArrayBackup = NULL;\r
1012 Initialized = FALSE;\r
1013 KeyInitialized = FALSE;\r
1014 ShowDownArrow = FALSE;\r
1015 ShowUpArrow = FALSE;\r
1016\r
1017 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1018 ValueArrayBackup = AllocateZeroPool (Tag->StorageWidth);\r
1019 ASSERT (ValueArrayBackup != NULL);\r
1020 CopyMem (ValueArrayBackup, ValueArray, ValueCount);\r
1021 TempValue = *(UINT8 *) (ValueArray);\r
1022 if (ValueArray[0] != 0x00) {\r
1023 Initialized = TRUE;\r
1024 }\r
1025\r
1026 for (Index = 0; ValueArray[Index] != 0x00; Index++)\r
1027 ;\r
1028 ValueCount = Index;\r
1029 } else {\r
1030 TempValue = *Value;\r
1031 }\r
1032\r
1033 Count = 0;\r
1034 PopUpWidth = 0;\r
1035\r
1036 FirstOptionFoundFlag = FALSE;\r
1037\r
1038 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
1039 ASSERT (StringPtr);\r
1040\r
1041 //\r
1042 // Initialization for "One of" pop-up menu\r
1043 //\r
1044 //\r
1045 // Get the number of one of options present and its size\r
1046 //\r
1047 for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {\r
1048 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1049 !MenuOption->Tags[Index].Suppress) {\r
1050 if (!FirstOptionFoundFlag) {\r
1051 FirstOptionFoundFlag = TRUE;\r
1052 }\r
1053\r
1054 Count++;\r
1055 Token = MenuOption->Tags[Index].Text;\r
1056\r
1057 //\r
1058 // If this is an ordered list that is initialized\r
1059 //\r
1060 if (Initialized) {\r
1061 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1062 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP;\r
1063 ValueBackup++\r
1064 ) {\r
1065 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1066 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1067 break;\r
1068 }\r
1069 }\r
1070 } else {\r
1071 StringPtr = GetToken (Token, MenuOption->Handle);\r
1072 }\r
1073\r
1074 if (StrLen (StringPtr) > PopUpWidth) {\r
1075 PopUpWidth = StrLen (StringPtr);\r
1076 }\r
1077\r
1078 FreePool (StringPtr);\r
1079 }\r
1080 }\r
1081 //\r
1082 // Perform popup menu initialization.\r
1083 //\r
1084 PopUpMenuLines = Count;\r
1085 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
1086\r
1087 SavedAttribute = gST->ConOut->Mode->Attribute;\r
1088 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1089\r
1090 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
1091 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
1092 }\r
1093\r
1094 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;\r
1095 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
1096 Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
1097 Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT;\r
1098\r
1099 MenuLinesInView = Bottom - Top - 1;\r
1100 if (MenuLinesInView >= PopUpMenuLines) {\r
1101 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
1102 Bottom = Top + PopUpMenuLines + 1;\r
1103 } else {\r
1104 TempValue = MenuOption->Tags[MenuOption->TagIndex + 1].Value;\r
1105 ShowDownArrow = TRUE;\r
1106 }\r
1107\r
1108 TopOptionIndex = 1;\r
1109 HighlightPosition = 0;\r
1110 do {\r
1111 if (Initialized) {\r
1112 for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) {\r
1113 //\r
1114 // Set the value for the item we are looking for\r
1115 //\r
1116 Count = ValueArrayBackup[Index2];\r
1117\r
1118 //\r
1119 // If we hit the end of the Array, we are complete\r
1120 //\r
1121 if (Count == 0) {\r
1122 break;\r
1123 }\r
1124\r
1125 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1126 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1127 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1128 ValueBackup++\r
1129 ) {\r
1130 //\r
1131 // We just found what we are looking for\r
1132 //\r
1133 if (MenuOption->Tags[ValueBackup].Value == Count) {\r
1134 //\r
1135 // As long as the two indexes aren't the same, we have\r
1136 // two different op-codes we need to swap internally\r
1137 //\r
1138 if (Index != ValueBackup) {\r
1139 //\r
1140 // Backup destination tag, then copy source to destination, then copy backup to source location\r
1141 //\r
1142 CopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1143 CopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG));\r
1144 CopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG));\r
1145 } else {\r
1146 //\r
1147 // If the indexes are the same, then the op-code is where he belongs\r
1148 //\r
1149 }\r
1150 }\r
1151 }\r
1152 } else {\r
1153 //\r
1154 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2\r
1155 //\r
1156 Index2--;\r
1157 }\r
1158 }\r
1159 }\r
1160 //\r
1161 // Clear that portion of the screen\r
1162 //\r
1163 ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);\r
1164\r
1165 //\r
1166 // Draw "One of" pop-up menu\r
1167 //\r
1168 Character = (CHAR16) BOXDRAW_DOWN_RIGHT;\r
1169 PrintCharAt (Start, Top, Character);\r
1170 for (Index = Start; Index + 2 < End; Index++) {\r
1171 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1172 Character = (CHAR16) GEOMETRICSHAPE_UP_TRIANGLE;\r
1173 } else {\r
1174 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1175 }\r
1176\r
1177 PrintChar (Character);\r
1178 }\r
1179\r
1180 Character = (CHAR16) BOXDRAW_DOWN_LEFT;\r
1181 PrintChar (Character);\r
1182 Character = (CHAR16) BOXDRAW_VERTICAL;\r
1183 for (Index = Top + 1; Index < Bottom; Index++) {\r
1184 PrintCharAt (Start, Index, Character);\r
1185 PrintCharAt (End - 1, Index, Character);\r
1186 }\r
1187 //\r
1188 // Display the One of options\r
1189 //\r
1190 Index2 = Top + 1;\r
1191 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1192 (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom);\r
1193 Index++\r
1194 ) {\r
1195 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1196 Token = MenuOption->Tags[Index].Text;\r
1197 if (Initialized) {\r
1198 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1199 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1200 ValueBackup++\r
1201 ) {\r
1202 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1203 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1204 break;\r
1205 }\r
1206 }\r
1207 } else {\r
1208 ValueBackup = (UINT8) Index;\r
1209 StringPtr = GetToken (Token, MenuOption->Handle);\r
1210 }\r
1211 //\r
1212 // If the string occupies multiple lines, truncate it to fit in one line,\r
1213 // and append a "..." for indication.\r
1214 //\r
1215 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
1216 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
1217 ASSERT (TempStringPtr != NULL);\r
1218 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
1219 FreePool (StringPtr);\r
1220 StringPtr = TempStringPtr;\r
1221 StrCat (StringPtr, (CHAR16 *) L"...");\r
1222 }\r
1223 //\r
1224 // Code to display the text should go here. Follwed by the [*]\r
1225 //\r
1226 if (MenuOption->Tags[ValueBackup].Suppress == TRUE) {\r
1227 //\r
1228 // Don't show the one, so decrease the Index2 for balance\r
1229 //\r
1230 Index2--;\r
1231 } else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) {\r
1232 //\r
1233 // Gray Out the one\r
1234 //\r
1235 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND);\r
1236 PrintStringAt (Start + 2, Index2, StringPtr);\r
1237 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1238 } else if (MenuOption->Tags[ValueBackup].Value == TempValue) {\r
1239 //\r
1240 // Highlight the selected one\r
1241 //\r
1242 gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);\r
1243 PrintStringAt (Start + 2, Index2, StringPtr);\r
1244 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1245 HighlightPosition = Index2;\r
1246 } else {\r
1247 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1248 PrintStringAt (Start + 2, Index2, StringPtr);\r
1249 }\r
1250\r
1251 FreePool (StringPtr);\r
1252 Index2 = Index2 + 1;\r
1253 }\r
1254 }\r
1255\r
1256 Character = (CHAR16) BOXDRAW_UP_RIGHT;\r
1257 PrintCharAt (Start, Bottom, Character);\r
1258 for (Index = Start; Index + 2 < End; Index++) {\r
1259 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1260 Character = (CHAR16) GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1261 } else {\r
1262 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1263 }\r
1264\r
1265 PrintChar (Character);\r
1266 }\r
1267\r
1268 Character = (CHAR16) BOXDRAW_UP_LEFT;\r
1269 PrintChar (Character);\r
1270 //\r
1271 // Get User selection and change TempValue if necessary\r
1272 //\r
1273 //\r
1274 // Stop: One of pop-up menu\r
1275 //\r
1276 Key.UnicodeChar = CHAR_NULL;\r
1277 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1278 Key.ScanCode = gDirection;\r
1279 gDirection = 0;\r
1280 goto TheKey;\r
1281 }\r
1282\r
1283 if (!KeyInitialized) {\r
1284 if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) {\r
1285 *KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key;\r
1286 } else {\r
1287 *KeyValue = MenuOption->ThisTag->Key;\r
1288 }\r
1289\r
1290 KeyInitialized = TRUE;\r
1291 }\r
1292\r
1293 WaitForKeyStroke (&Key);\r
1294\r
1295TheKey:\r
1296 switch (Key.UnicodeChar) {\r
1297 case '+':\r
1298 case '-':\r
1299 //\r
1300 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1301 // to create an ordered list of items\r
1302 //\r
1303 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1304 if (Key.UnicodeChar == '+') {\r
1305 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1306 //\r
1307 // Highlight reaches the top of the popup window, scroll one menu item.\r
1308 //\r
1309 TopOptionIndex--;\r
1310 ShowDownArrow = TRUE;\r
1311 }\r
1312\r
1313 if (TopOptionIndex == 1) {\r
1314 ShowUpArrow = FALSE;\r
1315 }\r
1316 } else {\r
1317 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1318 //\r
1319 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1320 //\r
1321 TopOptionIndex++;\r
1322 ShowUpArrow = TRUE;\r
1323 }\r
1324\r
1325 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1326 ShowDownArrow = FALSE;\r
1327 }\r
1328 }\r
1329\r
1330 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1331 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1332 Index++\r
1333 ) {\r
1334 if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1335 continue;\r
1336 }\r
1337\r
1338 if (Key.UnicodeChar == '+') {\r
1339 TempIndex = Index - 1;\r
1340 } else {\r
1341 TempIndex = Index + 1;\r
1342 }\r
1343 //\r
1344 // Is this the current tag we are on?\r
1345 //\r
1346 if (MenuOption->Tags[Index].Value == TempValue) {\r
1347 //\r
1348 // Is this prior tag a valid choice? If not, bail out\r
1349 //\r
1350 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1351 //\r
1352 // Copy the destination tag to the local variable\r
1353 //\r
1354 CopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG));\r
1355 //\r
1356 // Copy the current tag to the tag location before us\r
1357 //\r
1358 CopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1359 //\r
1360 // Copy the backed up tag to the current location\r
1361 //\r
1362 CopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG));\r
1363\r
1364 //\r
1365 // Adjust the array of values\r
1366 //\r
1367 for (Index = 0; Index < ValueCount; Index++) {\r
1368 if (ValueArrayBackup[Index] == (UINT8) TempValue) {\r
1369 if (Key.UnicodeChar == '+') {\r
1370 if (Index == 0) {\r
1371 //\r
1372 // It is the top of the array already\r
1373 //\r
1374 break;\r
1375 }\r
1376\r
1377 TempIndex = Index - 1;\r
1378 } else {\r
1379 if ((Index + 1) == ValueCount) {\r
1380 //\r
1381 // It is the bottom of the array already\r
1382 //\r
1383 break;\r
1384 }\r
1385\r
1386 TempIndex = Index + 1;\r
1387 }\r
1388\r
1389 ValueBackup = ValueArrayBackup[TempIndex];\r
1390 ValueArrayBackup[TempIndex] = ValueArrayBackup[Index];\r
1391 ValueArrayBackup[Index] = ValueBackup;\r
1392 Initialized = TRUE;\r
1393 break;\r
1394 }\r
1395 }\r
1396 break;\r
1397 } else {\r
1398 break;\r
1399 }\r
1400 }\r
1401 }\r
1402 }\r
1403 break;\r
1404\r
1405 case CHAR_NULL:\r
1406 switch (Key.ScanCode) {\r
1407 case SCAN_UP:\r
1408 case SCAN_DOWN:\r
1409 if (Key.ScanCode == SCAN_UP) {\r
1410 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1411 //\r
1412 // Highlight reaches the top of the popup window, scroll one menu item.\r
1413 //\r
1414 TopOptionIndex--;\r
1415 ShowDownArrow = TRUE;\r
1416 }\r
1417\r
1418 if (TopOptionIndex == 1) {\r
1419 ShowUpArrow = FALSE;\r
1420 }\r
1421 } else {\r
1422 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1423 //\r
1424 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1425 //\r
1426 TopOptionIndex++;\r
1427 ShowUpArrow = TRUE;\r
1428 }\r
1429\r
1430 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1431 ShowDownArrow = FALSE;\r
1432 }\r
1433 }\r
1434\r
1435 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1436 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1437 Index++\r
1438 ) {\r
1439 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1440 if (Initialized) {\r
1441 for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++)\r
1442 ;\r
1443\r
1444 //\r
1445 // Did we hit the end of the array? Either get the first TempValue or the next one\r
1446 //\r
1447 if (Key.ScanCode == SCAN_UP) {\r
1448 if (Index == 0) {\r
1449 TempValue = ValueArrayBackup[0];\r
1450 } else {\r
1451 TempValue = ValueArrayBackup[Index - 1];\r
1452 }\r
1453 } else {\r
1454 if ((Index + 1) == ValueCount) {\r
1455 TempValue = ValueArrayBackup[Index];\r
1456 } else {\r
1457 TempValue = ValueArrayBackup[Index + 1];\r
1458 }\r
1459 }\r
1460 break;\r
1461 } else {\r
1462 if (Key.ScanCode == SCAN_UP) {\r
1463 TempIndex = Index - 1;\r
1464\r
1465 //\r
1466 // Keep going until meets meaningful tag.\r
1467 //\r
1468 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1469 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1470 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1471 ||\r
1472 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1473 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1474 TempIndex--;\r
1475 }\r
1476 } else {\r
1477 TempIndex = Index + 1;\r
1478\r
1479 //\r
1480 // Keep going until meets meaningful tag.\r
1481 //\r
1482 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1483 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1484 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1485 ||\r
1486 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1487 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1488 TempIndex++;\r
1489 }\r
1490 }\r
1491 //\r
1492 // The option value is the same as what is stored in NV store. This is where we take action\r
1493 //\r
1494 if (MenuOption->Tags[Index].Value == TempValue) {\r
1495 //\r
1496 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option\r
1497 //\r
1498 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1499 TempValue = MenuOption->Tags[TempIndex].Value;\r
1500 *KeyValue = MenuOption->Tags[TempIndex].Key;\r
1501 } else {\r
1502 TempValue = MenuOption->Tags[Index].Value;\r
1503 *KeyValue = MenuOption->Tags[Index].Key;\r
1504 }\r
1505 break;\r
1506 }\r
1507 }\r
1508 }\r
1509 }\r
1510 break;\r
1511\r
1512 case SCAN_ESC:\r
1513 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1514 if (ValueArrayBackup != NULL) {\r
1515 FreePool (ValueArrayBackup);\r
1516 }\r
1517\r
1518 return EFI_DEVICE_ERROR;\r
1519\r
1520 default:\r
1521 break;\r
1522 }\r
1523\r
1524 break;\r
1525\r
1526 case CHAR_CARRIAGE_RETURN:\r
1527 //\r
1528 // return the current selection\r
1529 //\r
1530 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1531 CopyMem (ValueArray, ValueArrayBackup, ValueCount);\r
1532 FreePool (ValueArrayBackup);\r
1533 } else {\r
1534 *Value = TempValue;\r
1535 }\r
1536\r
1537 goto Done;\r
1538\r
1539 default:\r
1540 break;\r
1541 }\r
1542 } while (1);\r
1543\r
1544Done:\r
1545 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1546 return EFI_SUCCESS;\r
1547}\r
1548\r
1549EFI_STATUS\r
1550WaitForKeyStroke (\r
1551 OUT EFI_INPUT_KEY *Key\r
1552 )\r
1553{\r
1554 EFI_STATUS Status;\r
1555\r
1556 do {\r
1557 UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
1558 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
1559 } while (EFI_ERROR(Status));\r
1560\r
1561 return Status;\r
1562}\r