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