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