]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/UserInterface/SetupBrowser/Dxe/InputHandler.c
Initial import.
[mirror_edk2.git] / EdkModulePkg / Universal / UserInterface / SetupBrowser / Dxe / InputHandler.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, 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#include "Setup.h"\r
25#include "Ui.h"\r
26#include "Colors.h"\r
27\r
28#ifndef EFI_MAX\r
29#define EFI_MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))\r
30#endif\r
31\r
32EFI_STATUS\r
33ReadString (\r
34 IN UI_MENU_OPTION *MenuOption,\r
35 OUT CHAR16 *StringPtr\r
36 )\r
37{\r
38 EFI_STATUS Status;\r
39 EFI_INPUT_KEY Key;\r
40 CHAR16 NullCharacter;\r
41 UINTN ScreenSize;\r
42 EFI_TAG *Tag;\r
43 CHAR16 Space[2];\r
44 CHAR16 KeyPad[2];\r
45 BOOLEAN SelectionComplete;\r
46 CHAR16 *TempString;\r
47 CHAR16 *BufferedString;\r
48 UINTN Index;\r
49 UINTN Count;\r
50 UINTN Start;\r
51 UINTN Top;\r
52 CHAR16 *PromptForDataString;\r
53 UINTN DimensionsWidth;\r
54 UINTN DimensionsHeight;\r
55 BOOLEAN CursorVisible;\r
56\r
57 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
58 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
59\r
60 PromptForDataString = GetToken (STRING_TOKEN (PROMPT_FOR_DATA), gHiiHandle);\r
61\r
62 NullCharacter = CHAR_NULL;\r
63 ScreenSize = GetStringWidth (PromptForDataString) / 2;\r
64 Tag = MenuOption->ThisTag;\r
65 Space[0] = L' ';\r
66 Space[1] = CHAR_NULL;\r
67 SelectionComplete = FALSE;\r
68\r
69 TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
70 ASSERT (TempString);\r
71\r
72 if (ScreenSize < (Tag->Maximum / (UINTN) 2)) {\r
73 ScreenSize = Tag->Maximum / 2;\r
74 }\r
75\r
76 if ((ScreenSize + 2) > DimensionsWidth) {\r
77 ScreenSize = DimensionsWidth - 2;\r
78 }\r
79\r
80 BufferedString = AllocateZeroPool (ScreenSize * 2);\r
81 ASSERT (BufferedString);\r
82\r
83 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gScreenDimensions.LeftColumn + 1;\r
84 Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;\r
85\r
86 //\r
87 // Display prompt for string\r
88 //\r
89 CreatePopUp (ScreenSize, 4, &NullCharacter, PromptForDataString, Space, &NullCharacter);\r
90\r
91 gBS->FreePool (PromptForDataString);\r
92\r
93 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
94\r
95 CursorVisible = gST->ConOut->Mode->CursorVisible;\r
96 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
97\r
98 do {\r
99 Status = WaitForKeyStroke (&Key);\r
100\r
101 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
102 switch (Key.UnicodeChar) {\r
103 case CHAR_NULL:\r
104 switch (Key.ScanCode) {\r
105 case SCAN_LEFT:\r
106 break;\r
107\r
108 case SCAN_RIGHT:\r
109 break;\r
110\r
111 case SCAN_ESC:\r
112 gBS->FreePool (TempString);\r
113 gBS->FreePool (BufferedString);\r
114 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
115 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
116 return EFI_DEVICE_ERROR;\r
117\r
118 default:\r
119 break;\r
120 }\r
121\r
122 break;\r
123\r
124 case CHAR_CARRIAGE_RETURN:\r
125 if (GetStringWidth (StringPtr) >= MenuOption->ThisTag->Minimum) {\r
126 SelectionComplete = TRUE;\r
127 gBS->FreePool (TempString);\r
128 gBS->FreePool (BufferedString);\r
129 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
130 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
131 return EFI_SUCCESS;\r
132 } else {\r
133 ScreenSize = GetStringWidth (gMiniString) / 2;\r
134 CreatePopUp (ScreenSize, 4, &NullCharacter, gMiniString, gPressEnter, &NullCharacter);\r
135 //\r
136 // Simply create a popup to tell the user that they had typed in too few characters.\r
137 // To save code space, we can then treat this as an error and return back to the menu.\r
138 //\r
139 do {\r
140 Status = WaitForKeyStroke (&Key);\r
141 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
142 gBS->FreePool (TempString);\r
143 gBS->FreePool (BufferedString);\r
144 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
145 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
146 return EFI_DEVICE_ERROR;\r
147 }\r
148\r
149 break;\r
150\r
151 case CHAR_BACKSPACE:\r
152 if (StringPtr[0] != CHAR_NULL) {\r
153 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
154 TempString[Index] = StringPtr[Index];\r
155 }\r
156 //\r
157 // Effectively truncate string by 1 character\r
158 //\r
159 TempString[Index - 1] = CHAR_NULL;\r
160 StrCpy (StringPtr, TempString);\r
161 }\r
162\r
163 default:\r
164 //\r
165 // If it is the beginning of the string, don't worry about checking maximum limits\r
166 //\r
167 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
168 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
169 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
170 } else if ((GetStringWidth (StringPtr) < MenuOption->ThisTag->Maximum) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
171 KeyPad[0] = Key.UnicodeChar;\r
172 KeyPad[1] = CHAR_NULL;\r
173 StrCat (StringPtr, KeyPad);\r
174 StrCat (TempString, KeyPad);\r
175 }\r
176 //\r
177 // If the width of the input string is now larger than the screen, we nee to\r
178 // adjust the index to start printing portions of the string\r
179 //\r
180 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
181\r
182 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
183\r
184 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
185 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
186 } else {\r
187 Index = 0;\r
188 }\r
189\r
190 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
191 BufferedString[Count] = StringPtr[Index];\r
192 }\r
193\r
194 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
195 break;\r
196 }\r
197\r
198 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
199 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
200 } while (!SelectionComplete);\r
201 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
202 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
203 return Status;\r
204}\r
205\r
206EFI_STATUS\r
207ReadPassword (\r
208 IN UI_MENU_OPTION *MenuOption,\r
209 IN BOOLEAN PromptForPassword,\r
210 IN EFI_TAG *Tag,\r
211 IN EFI_IFR_DATA_ARRAY *PageData,\r
212 IN BOOLEAN SecondEntry,\r
213 IN EFI_FILE_FORM_TAGS *FileFormTags,\r
214 OUT CHAR16 *StringPtr\r
215 )\r
216{\r
217 EFI_STATUS Status;\r
218 UINTN PasswordSize;\r
219 UINTN ScreenSize;\r
220 CHAR16 NullCharacter;\r
221 CHAR16 Space[2];\r
222 EFI_INPUT_KEY Key;\r
223 CHAR16 KeyPad[2];\r
224 UINTN Index;\r
225 UINTN Start;\r
226 UINTN Top;\r
227 CHAR16 *TempString;\r
228 CHAR16 *TempString2;\r
229 BOOLEAN Confirmation;\r
230 BOOLEAN ConfirmationComplete;\r
231 EFI_HII_CALLBACK_PACKET *Packet;\r
232 EFI_FORM_CALLBACK_PROTOCOL *FormCallback;\r
233 EFI_VARIABLE_DEFINITION *VariableDefinition;\r
234 UINTN DimensionsWidth;\r
235 UINTN DimensionsHeight;\r
236 EFI_IFR_DATA_ENTRY *DataEntry;\r
237\r
238 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
239 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
240\r
241 VariableDefinition = NULL;\r
242 PasswordSize = 0;\r
243 NullCharacter = CHAR_NULL;\r
244 Space[0] = L' ';\r
245 Space[1] = CHAR_NULL;\r
246 Confirmation = FALSE;\r
247 ConfirmationComplete = FALSE;\r
248 Status = EFI_SUCCESS;\r
249 FormCallback = NULL;\r
250 Packet = NULL;\r
251\r
252 //\r
253 // Remember that dynamic pages in an environment where all pages are not\r
254 // dynamic require us to call back to the user to give them an opportunity\r
255 // to register fresh information in the HII database so that we can extract it.\r
256 //\r
257 Status = gBS->HandleProtocol (\r
258 (VOID *) (UINTN) MenuOption->Tags[0].CallbackHandle,\r
259 &gEfiFormCallbackProtocolGuid,\r
260 (VOID **) &FormCallback\r
261 );\r
262\r
263 TempString = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
264 TempString2 = AllocateZeroPool (MenuOption->ThisTag->Maximum * 2);\r
265\r
266 ASSERT (TempString);\r
267 ASSERT (TempString2);\r
268\r
269 if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
270 //\r
271 // Password requires a callback to determine if a password exists\r
272 //\r
273 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
274 DataEntry->OpCode = EFI_IFR_PASSWORD_OP;\r
275 DataEntry->Length = 3;\r
276\r
277 ExtractRequestedNvMap (FileFormTags, Tag->VariableNumber, &VariableDefinition);\r
278\r
279 //\r
280 // The user is about to be prompted with a password field, Data = 0 (Return Status determines the type of prompt)\r
281 //\r
282 DataEntry->Data = (VOID *) (UINTN) (UINT8) (0 + SecondEntry * 2);\r
283 PageData->NvRamMap = VariableDefinition->NvRamMap;\r
284\r
285 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
286 Status = FormCallback->Callback (\r
287 FormCallback,\r
288 Tag->Key,\r
289 PageData,\r
290 &Packet\r
291 );\r
292 }\r
293 //\r
294 // If error on return, continue with the reading of a typed in password to verify user knows password\r
295 // If no error, there is no password set, so prompt for new password\r
296 // if the previous callback was to verify the user knew password, and user typed it correctly - should return no error\r
297 //\r
298 if (!EFI_ERROR (Status)) {\r
299 PromptForPassword = FALSE;\r
300\r
301 //\r
302 // Simulate this as the second entry into this routine for an interactive behavior\r
303 //\r
304 SecondEntry = TRUE;\r
305 } else if (Status == EFI_NOT_READY) {\r
306Error:\r
307 if (Packet != NULL) {\r
308 //\r
309 // Upon error, we will likely receive a string to print out\r
310 // Display error popup\r
311 //\r
312 ScreenSize = EFI_MAX(GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2;\r
313 CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);\r
314 gBS->FreePool (Packet);\r
315\r
316 do {\r
317 Status = WaitForKeyStroke (&Key);\r
318 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
319 }\r
320\r
321 gBS->FreePool (TempString);\r
322 gBS->FreePool (TempString2);\r
323 return EFI_NOT_READY;\r
324 }\r
325 }\r
326\r
327 do {\r
328 //\r
329 // Display PopUp Screen\r
330 //\r
331 ScreenSize = GetStringWidth (gPromptForNewPassword) / 2;\r
332 if (GetStringWidth (gConfirmPassword) / 2 > ScreenSize) {\r
333 ScreenSize = GetStringWidth (gConfirmPassword) / 2;\r
334 }\r
335\r
336 Start = (DimensionsWidth - ScreenSize - 4) / 2 + gScreenDimensions.LeftColumn + 2;\r
337 Top = ((DimensionsHeight - 6) / 2) + gScreenDimensions.TopRow - 1;\r
338\r
339 if (!Confirmation) {\r
340 if (PromptForPassword) {\r
341 CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForPassword, Space, &NullCharacter);\r
342 } else {\r
343 CreatePopUp (ScreenSize, 4, &NullCharacter, gPromptForNewPassword, Space, &NullCharacter);\r
344 }\r
345 } else {\r
346 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmPassword, Space, &NullCharacter);\r
347 StringPtr[0] = CHAR_NULL;\r
348 }\r
349\r
350 do {\r
351 Status = WaitForKeyStroke (&Key);\r
352\r
353 switch (Key.UnicodeChar) {\r
354 case CHAR_NULL:\r
355 if (Key.ScanCode == SCAN_ESC) {\r
356 return EFI_NOT_READY;\r
357 }\r
358\r
359 ConfirmationComplete = FALSE;\r
360 break;\r
361\r
362 case CHAR_CARRIAGE_RETURN:\r
363 if (Tag->Flags & EFI_IFR_FLAG_INTERACTIVE) {\r
364 //\r
365 // User just typed a string in\r
366 //\r
367 DataEntry = (EFI_IFR_DATA_ENTRY *) (PageData + 1);\r
368 DataEntry->OpCode = EFI_IFR_PASSWORD_OP;\r
369\r
370 //\r
371 // If the user just typed in a password, Data = 1\r
372 // If the user just typed in a password to confirm the previous password, Data = 2\r
373 //\r
374 if (!Confirmation) {\r
375 DataEntry->Length = 3;\r
376 DataEntry->Data = (VOID *) (UINTN) (UINT8) (1 + SecondEntry * 2);\r
377\r
378 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
379 Status = FormCallback->Callback (\r
380 FormCallback,\r
381 Tag->Key,\r
382 PageData,\r
383 &Packet\r
384 );\r
385 }\r
386\r
387 DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);\r
388 DataEntry->Data = (VOID *) TempString;\r
389 } else {\r
390 DataEntry->Length = 3;\r
391 DataEntry->Data = (VOID *) (UINTN) (UINT8) (2 + SecondEntry * 2);\r
392\r
393 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
394 Status = FormCallback->Callback (\r
395 FormCallback,\r
396 Tag->Key,\r
397 PageData,\r
398 &Packet\r
399 );\r
400 }\r
401\r
402 DataEntry->Length = sizeof (EFI_IFR_DATA_ENTRY);\r
403 DataEntry->Data = (VOID *) TempString2;\r
404 }\r
405\r
406 if ((FormCallback != NULL) && (FormCallback->Callback != NULL)) {\r
407 Status = FormCallback->Callback (\r
408 FormCallback,\r
409 Tag->Key,\r
410 PageData,\r
411 &Packet\r
412 );\r
413 }\r
414 //\r
415 // If this was the confirmation round of callbacks\r
416 // and an error comes back, display an error\r
417 //\r
418 if (Confirmation) {\r
419 if (EFI_ERROR (Status)) {\r
420 if (Packet->String == NULL) {\r
421 ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2;\r
422 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);\r
423 } else {\r
424 ScreenSize = EFI_MAX (GetStringWidth (Packet->String), GetStringWidth (gPressEnter)) / 2;\r
425 CreatePopUp (ScreenSize, 4, &NullCharacter, Packet->String, gPressEnter, &NullCharacter);\r
426 gBS->FreePool (Packet);\r
427 }\r
428\r
429 StringPtr[0] = CHAR_NULL;\r
430 do {\r
431 Status = WaitForKeyStroke (&Key);\r
432\r
433 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
434 gBS->FreePool (TempString);\r
435 gBS->FreePool (TempString2);\r
436 return EFI_NOT_READY;\r
437 }\r
438 } while (1);\r
439 } else {\r
440 gBS->FreePool (TempString);\r
441 gBS->FreePool (TempString2);\r
442 return EFI_NOT_READY;\r
443 }\r
444 } else {\r
445 //\r
446 // User typed a string in and it wasn't valid somehow from the callback\r
447 // For instance, callback may have said that some invalid characters were contained in the string\r
448 //\r
449 if (Status == EFI_NOT_READY) {\r
450 goto Error;\r
451 }\r
452\r
453 if (PromptForPassword && EFI_ERROR (Status)) {\r
454 gBS->FreePool (TempString);\r
455 gBS->FreePool (TempString2);\r
456 return EFI_DEVICE_ERROR;\r
457 }\r
458 }\r
459 }\r
460\r
461 if (Confirmation) {\r
462 //\r
463 // Compare tempstring and tempstring2, if the same, return with StringPtr success\r
464 // Otherwise, kick and error box, and return an error\r
465 //\r
466 if (StrCmp (TempString, TempString2) == 0) {\r
467 gBS->FreePool (TempString);\r
468 gBS->FreePool (TempString2);\r
469 return EFI_SUCCESS;\r
470 } else {\r
471 ScreenSize = EFI_MAX (GetStringWidth (gConfirmError), GetStringWidth (gPressEnter)) / 2;\r
472 CreatePopUp (ScreenSize, 4, &NullCharacter, gConfirmError, gPressEnter, &NullCharacter);\r
473 StringPtr[0] = CHAR_NULL;\r
474 do {\r
475 Status = WaitForKeyStroke (&Key);\r
476 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
477 gBS->FreePool (TempString);\r
478 gBS->FreePool (TempString2);\r
479 return EFI_DEVICE_ERROR;\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 gBS->FreePool (TempString);\r
490 gBS->FreePool (TempString2);\r
491 return EFI_SUCCESS;\r
492 } else {\r
493 //\r
494 // If the two passwords were not the same kick an error popup\r
495 //\r
496 Confirmation = TRUE;\r
497 ConfirmationComplete = TRUE;\r
498 break;\r
499 }\r
500\r
501 case CHAR_BACKSPACE:\r
502 if (StringPtr[0] != CHAR_NULL) {\r
503 if (!Confirmation) {\r
504 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
505 TempString[Index] = StringPtr[Index];\r
506 }\r
507 //\r
508 // Effectively truncate string by 1 character\r
509 //\r
510 TempString[Index - 1] = CHAR_NULL;\r
511 StrCpy (StringPtr, TempString);\r
512 } else {\r
513 for (Index = 0; StringPtr[Index] != CHAR_NULL; Index++) {\r
514 TempString2[Index] = StringPtr[Index];\r
515 }\r
516 //\r
517 // Effectively truncate string by 1 character\r
518 //\r
519 TempString2[Index - 1] = CHAR_NULL;\r
520 StrCpy (StringPtr, TempString2);\r
521 }\r
522\r
523 ConfirmationComplete = FALSE;\r
524 } else {\r
525 ConfirmationComplete = FALSE;\r
526 }\r
527\r
528 //\r
529 // Must be a character we are interested in!\r
530 //\r
531 default:\r
532 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
533 if (!Confirmation) {\r
534 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
535 StrnCpy (TempString, &Key.UnicodeChar, 1);\r
536 } else {\r
537 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
538 StrnCpy (TempString2, &Key.UnicodeChar, 1);\r
539 ConfirmationComplete = FALSE;\r
540 }\r
541 } else if ((GetStringWidth (StringPtr) / 2 <= (UINTN) (MenuOption->ThisTag->Maximum - 1) / 2) &&\r
542 (Key.UnicodeChar != CHAR_BACKSPACE)\r
543 ) {\r
544 KeyPad[0] = Key.UnicodeChar;\r
545 KeyPad[1] = CHAR_NULL;\r
546 if (!Confirmation) {\r
547 StrCat (StringPtr, KeyPad);\r
548 StrCat (TempString, KeyPad);\r
549 } else {\r
550 StrCat (StringPtr, KeyPad);\r
551 StrCat (TempString2, KeyPad);\r
552 }\r
553 }\r
554\r
555 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
556 for (Index = 1; Index < ScreenSize; Index++) {\r
557 PrintCharAt (Start + Index, Top + 3, L' ');\r
558 }\r
559\r
560 gST->ConOut->SetCursorPosition (\r
561 gST->ConOut,\r
562 (DimensionsWidth - GetStringWidth (StringPtr) / 2) / 2 + gScreenDimensions.LeftColumn,\r
563 Top + 3\r
564 );\r
565 for (Index = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++) {\r
566 PrintChar (L'*');\r
567 }\r
568\r
569 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
570 break;\r
571 }\r
572 //\r
573 // end switch\r
574 //\r
575 } while (!ConfirmationComplete);\r
576\r
577 } while (1);\r
578 gBS->FreePool (TempString);\r
579 gBS->FreePool (TempString2);\r
580 return Status;\r
581}\r
582\r
583VOID\r
584EncodePassword (\r
585 IN CHAR16 *Password,\r
586 IN UINT8 MaxSize\r
587 )\r
588{\r
589 UINTN Index;\r
590 UINTN Loop;\r
591 CHAR16 *Buffer;\r
592 CHAR16 *Key;\r
593\r
594 Key = (CHAR16 *) L"MAR10648567";\r
595 Buffer = AllocateZeroPool (MaxSize);\r
596\r
597 ASSERT (Buffer);\r
598\r
599 for (Index = 0; Key[Index] != 0; Index++) {\r
600 for (Loop = 0; Loop < (UINT8) (MaxSize / 2); Loop++) {\r
601 Buffer[Loop] = (CHAR16) (Password[Loop] ^ Key[Index]);\r
602 }\r
603 }\r
604\r
605 CopyMem (Password, Buffer, MaxSize);\r
606\r
607 gBS->FreePool (Buffer);\r
608 return ;\r
609}\r
610\r
611EFI_STATUS\r
612GetNumericInput (\r
613 IN UI_MENU_OPTION *MenuOption,\r
614 IN EFI_FILE_FORM_TAGS *FileFormTagsHead,\r
615 IN BOOLEAN ManualInput,\r
616 IN EFI_TAG *Tag,\r
617 IN UINTN NumericType,\r
618 OUT UINT16 *Value\r
619 )\r
620/*++\r
621\r
622Routine Description:\r
623\r
624 This routine reads a numeric value from the user input. \r
625\r
626Arguments:\r
627\r
628 MenuOption - Pointer to the current input menu.\r
629\r
630 FileFormTagsHead - Pointer to the root of formset.\r
631\r
632 ManualInput - If the input is manual or not.\r
633\r
634 Tag - Pointer to all the attributes and values associated with a tag.\r
635 \r
636 Value - Pointer to the numeric value that is going to be read.\r
637\r
638Returns: \r
639\r
640 EFI_SUCCESS - If numerical input is read successfully\r
641 EFI_DEVICE_ERROR - If operation fails\r
642 \r
643--*/\r
644{\r
645 EFI_INPUT_KEY Key;\r
646 BOOLEAN SelectionComplete;\r
647 UINTN Column;\r
648 UINTN Row;\r
649 CHAR16 FormattedNumber[6];\r
650 UINTN PreviousNumber[6];\r
651 INTN Number;\r
652 UINTN Count;\r
653 UINT16 BackupValue;\r
654 STRING_REF PopUp;\r
655 CHAR16 NullCharacter;\r
656 CHAR16 *StringPtr;\r
657 EFI_FILE_FORM_TAGS *FileFormTags;\r
658 EFI_STATUS Status;\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 Status = 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 Status = WaitForKeyStroke (&Key);\r
883\r
884 switch (Key.UnicodeChar) {\r
885\r
886 case CHAR_CARRIAGE_RETURN:\r
887 SelectionComplete = TRUE;\r
888 gBS->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_STATUS Status;\r
989 EFI_INPUT_KEY Key;\r
990 UINTN Index;\r
991 UINTN TempIndex;\r
992 CHAR16 *StringPtr;\r
993 CHAR16 *TempStringPtr;\r
994 UINT16 Token;\r
995 UINTN Index2;\r
996 UINTN TopOptionIndex;\r
997 UINTN HighlightPosition;\r
998 UINTN Start;\r
999 UINTN End;\r
1000 UINTN Top;\r
1001 UINTN Bottom;\r
1002 UINT16 TempValue;\r
1003 UINTN Count;\r
1004 UINTN PopUpMenuLines;\r
1005 UINTN MenuLinesInView;\r
1006 UINTN PopUpWidth;\r
1007 CHAR16 Character;\r
1008 UINTN FirstOption;\r
1009 BOOLEAN FirstOptionFoundFlag;\r
1010 INT32 SavedAttribute;\r
1011 EFI_TAG TagBackup;\r
1012 UINT8 *ValueArray;\r
1013 UINT8 *ValueArrayBackup;\r
1014 UINT8 ValueBackup;\r
1015 BOOLEAN Initialized;\r
1016 BOOLEAN KeyInitialized;\r
1017 BOOLEAN ShowDownArrow;\r
1018 BOOLEAN ShowUpArrow;\r
1019 UINTN DimensionsWidth;\r
1020 UINTN DimensionsHeight;\r
1021\r
1022 DimensionsWidth = gScreenDimensions.RightColumn - gScreenDimensions.LeftColumn;\r
1023 DimensionsHeight = gScreenDimensions.BottomRow - gScreenDimensions.TopRow;\r
1024\r
1025 TempValue = 0;\r
1026 TempIndex = 0;\r
1027 ValueArray = (UINT8 *) Value;\r
1028 ValueArrayBackup = NULL;\r
1029 Initialized = FALSE;\r
1030 KeyInitialized = FALSE;\r
1031 ShowDownArrow = FALSE;\r
1032 ShowUpArrow = FALSE;\r
1033\r
1034 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1035 ValueArrayBackup = AllocateZeroPool (Tag->StorageWidth);\r
1036 ASSERT (ValueArrayBackup != NULL);\r
1037 CopyMem (ValueArrayBackup, ValueArray, ValueCount);\r
1038 TempValue = *(UINT8 *) (ValueArray);\r
1039 if (ValueArray[0] != 0x00) {\r
1040 Initialized = TRUE;\r
1041 }\r
1042\r
1043 for (Index = 0; ValueArray[Index] != 0x00; Index++)\r
1044 ;\r
1045 ValueCount = Index;\r
1046 } else {\r
1047 TempValue = *Value;\r
1048 }\r
1049\r
1050 Count = 0;\r
1051 PopUpWidth = 0;\r
1052\r
1053 FirstOption = MenuOption->TagIndex;\r
1054 FirstOptionFoundFlag = FALSE;\r
1055\r
1056 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
1057 ASSERT (StringPtr);\r
1058\r
1059 //\r
1060 // Initialization for "One of" pop-up menu\r
1061 //\r
1062 //\r
1063 // Get the number of one of options present and its size\r
1064 //\r
1065 for (Index = MenuOption->TagIndex; MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP; Index++) {\r
1066 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1067 !MenuOption->Tags[Index].Suppress) {\r
1068 if (!FirstOptionFoundFlag) {\r
1069 FirstOption = Index;\r
1070 FirstOptionFoundFlag = TRUE;\r
1071 }\r
1072\r
1073 Count++;\r
1074 Token = MenuOption->Tags[Index].Text;\r
1075\r
1076 //\r
1077 // If this is an ordered list that is initialized\r
1078 //\r
1079 if (Initialized) {\r
1080 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1081 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_OP;\r
1082 ValueBackup++\r
1083 ) {\r
1084 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1085 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1086 break;\r
1087 }\r
1088 }\r
1089 } else {\r
1090 StringPtr = GetToken (Token, MenuOption->Handle);\r
1091 }\r
1092\r
1093 if (StrLen (StringPtr) > PopUpWidth) {\r
1094 PopUpWidth = StrLen (StringPtr);\r
1095 }\r
1096\r
1097 gBS->FreePool (StringPtr);\r
1098 }\r
1099 }\r
1100 //\r
1101 // Perform popup menu initialization.\r
1102 //\r
1103 PopUpMenuLines = Count;\r
1104 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
1105\r
1106 SavedAttribute = gST->ConOut->Mode->Attribute;\r
1107 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1108\r
1109 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
1110 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
1111 }\r
1112\r
1113 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gScreenDimensions.LeftColumn;\r
1114 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
1115 Top = gScreenDimensions.TopRow + NONE_FRONT_PAGE_HEADER_HEIGHT;\r
1116 Bottom = gScreenDimensions.BottomRow - STATUS_BAR_HEIGHT - FOOTER_HEIGHT;\r
1117\r
1118 MenuLinesInView = Bottom - Top - 1;\r
1119 if (MenuLinesInView >= PopUpMenuLines) {\r
1120 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
1121 Bottom = Top + PopUpMenuLines + 1;\r
1122 } else {\r
1123 TempValue = MenuOption->Tags[MenuOption->TagIndex + 1].Value;\r
1124 ShowDownArrow = TRUE;\r
1125 }\r
1126\r
1127 TopOptionIndex = 1;\r
1128 HighlightPosition = 0;\r
1129 do {\r
1130 if (Initialized) {\r
1131 for (Index = MenuOption->TagIndex, Index2 = 0; Index2 < ValueCount; Index++, Index2++) {\r
1132 //\r
1133 // Set the value for the item we are looking for\r
1134 //\r
1135 Count = ValueArrayBackup[Index2];\r
1136\r
1137 //\r
1138 // If we hit the end of the Array, we are complete\r
1139 //\r
1140 if (Count == 0) {\r
1141 break;\r
1142 }\r
1143\r
1144 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1145 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1146 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1147 ValueBackup++\r
1148 ) {\r
1149 //\r
1150 // We just found what we are looking for\r
1151 //\r
1152 if (MenuOption->Tags[ValueBackup].Value == Count) {\r
1153 //\r
1154 // As long as the two indexes aren't the same, we have\r
1155 // two different op-codes we need to swap internally\r
1156 //\r
1157 if (Index != ValueBackup) {\r
1158 //\r
1159 // Backup destination tag, then copy source to destination, then copy backup to source location\r
1160 //\r
1161 CopyMem (&TagBackup, &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1162 CopyMem (&MenuOption->Tags[Index], &MenuOption->Tags[ValueBackup], sizeof (EFI_TAG));\r
1163 CopyMem (&MenuOption->Tags[ValueBackup], &TagBackup, sizeof (EFI_TAG));\r
1164 } else {\r
1165 //\r
1166 // If the indexes are the same, then the op-code is where he belongs\r
1167 //\r
1168 }\r
1169 }\r
1170 }\r
1171 } else {\r
1172 //\r
1173 // Since this wasn't an option op-code (likely the ordered list op-code) decerement Index2\r
1174 //\r
1175 Index2--;\r
1176 }\r
1177 }\r
1178 }\r
1179 //\r
1180 // Clear that portion of the screen\r
1181 //\r
1182 ClearLines (Start, End, Top, Bottom, POPUP_TEXT | POPUP_BACKGROUND);\r
1183\r
1184 //\r
1185 // Draw "One of" pop-up menu\r
1186 //\r
1187 Character = (CHAR16) BOXDRAW_DOWN_RIGHT;\r
1188 PrintCharAt (Start, Top, Character);\r
1189 for (Index = Start; Index + 2 < End; Index++) {\r
1190 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1191 Character = (CHAR16) GEOMETRICSHAPE_UP_TRIANGLE;\r
1192 } else {\r
1193 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1194 }\r
1195\r
1196 PrintChar (Character);\r
1197 }\r
1198\r
1199 Character = (CHAR16) BOXDRAW_DOWN_LEFT;\r
1200 PrintChar (Character);\r
1201 Character = (CHAR16) BOXDRAW_VERTICAL;\r
1202 for (Index = Top + 1; Index < Bottom; Index++) {\r
1203 PrintCharAt (Start, Index, Character);\r
1204 PrintCharAt (End - 1, Index, Character);\r
1205 }\r
1206 //\r
1207 // Display the One of options\r
1208 //\r
1209 Index2 = Top + 1;\r
1210 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1211 (MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP) && (Index2 < Bottom);\r
1212 Index++\r
1213 ) {\r
1214 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1215 Token = MenuOption->Tags[Index].Text;\r
1216 if (Initialized) {\r
1217 for (ValueBackup = (UINT8) MenuOption->TagIndex;\r
1218 MenuOption->Tags[ValueBackup].Operand != EFI_IFR_END_ONE_OF_OP;\r
1219 ValueBackup++\r
1220 ) {\r
1221 if (MenuOption->Tags[ValueBackup].Value == ((UINT8 *) ValueArrayBackup)[Index - MenuOption->TagIndex - 1]) {\r
1222 StringPtr = GetToken (MenuOption->Tags[ValueBackup].Text, MenuOption->Handle);\r
1223 break;\r
1224 }\r
1225 }\r
1226 } else {\r
1227 ValueBackup = (UINT8) Index;\r
1228 StringPtr = GetToken (Token, MenuOption->Handle);\r
1229 }\r
1230 //\r
1231 // If the string occupies multiple lines, truncate it to fit in one line,\r
1232 // and append a "..." for indication.\r
1233 //\r
1234 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
1235 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
1236 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
1237 gBS->FreePool (StringPtr);\r
1238 StringPtr = TempStringPtr;\r
1239 StrCat (StringPtr, (CHAR16 *) L"...");\r
1240 }\r
1241 //\r
1242 // Code to display the text should go here. Follwed by the [*]\r
1243 //\r
1244 if (MenuOption->Tags[ValueBackup].Suppress == TRUE) {\r
1245 //\r
1246 // Don't show the one, so decrease the Index2 for balance\r
1247 //\r
1248 Index2--;\r
1249 } else if (MenuOption->Tags[ValueBackup].GrayOut == TRUE) {\r
1250 //\r
1251 // Gray Out the one\r
1252 //\r
1253 gST->ConOut->SetAttribute (gST->ConOut, FIELD_TEXT_GRAYED | POPUP_BACKGROUND);\r
1254 PrintStringAt (Start + 2, Index2, StringPtr);\r
1255 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1256 } else if (MenuOption->Tags[ValueBackup].Value == TempValue) {\r
1257 //\r
1258 // Highlight the selected one\r
1259 //\r
1260 gST->ConOut->SetAttribute (gST->ConOut, PICKLIST_HIGHLIGHT_TEXT | PICKLIST_HIGHLIGHT_BACKGROUND);\r
1261 PrintStringAt (Start + 2, Index2, StringPtr);\r
1262 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1263 HighlightPosition = Index2;\r
1264 } else {\r
1265 gST->ConOut->SetAttribute (gST->ConOut, POPUP_TEXT | POPUP_BACKGROUND);\r
1266 PrintStringAt (Start + 2, Index2, StringPtr);\r
1267 }\r
1268\r
1269 gBS->FreePool (StringPtr);\r
1270 Index2 = Index2 + 1;\r
1271 }\r
1272 }\r
1273\r
1274 Character = (CHAR16) BOXDRAW_UP_RIGHT;\r
1275 PrintCharAt (Start, Bottom, Character);\r
1276 for (Index = Start; Index + 2 < End; Index++) {\r
1277 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1278 Character = (CHAR16) GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1279 } else {\r
1280 Character = (CHAR16) BOXDRAW_HORIZONTAL;\r
1281 }\r
1282\r
1283 PrintChar (Character);\r
1284 }\r
1285\r
1286 Character = (CHAR16) BOXDRAW_UP_LEFT;\r
1287 PrintChar (Character);\r
1288 //\r
1289 // Get User selection and change TempValue if necessary\r
1290 //\r
1291 //\r
1292 // Stop: One of pop-up menu\r
1293 //\r
1294 Key.UnicodeChar = CHAR_NULL;\r
1295 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1296 Key.ScanCode = gDirection;\r
1297 gDirection = 0;\r
1298 goto TheKey;\r
1299 }\r
1300\r
1301 if (!KeyInitialized) {\r
1302 if (MenuOption->ThisTag->Operand == EFI_IFR_ONE_OF_OP) {\r
1303 *KeyValue = MenuOption->Tags[MenuOption->TagIndex + 1].Key;\r
1304 } else {\r
1305 *KeyValue = MenuOption->ThisTag->Key;\r
1306 }\r
1307\r
1308 KeyInitialized = TRUE;\r
1309 }\r
1310\r
1311 Status = WaitForKeyStroke (&Key);\r
1312\r
1313TheKey:\r
1314 switch (Key.UnicodeChar) {\r
1315 case '+':\r
1316 case '-':\r
1317 //\r
1318 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1319 // to create an ordered list of items\r
1320 //\r
1321 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1322 if (Key.UnicodeChar == '+') {\r
1323 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1324 //\r
1325 // Highlight reaches the top of the popup window, scroll one menu item.\r
1326 //\r
1327 TopOptionIndex--;\r
1328 ShowDownArrow = TRUE;\r
1329 }\r
1330\r
1331 if (TopOptionIndex == 1) {\r
1332 ShowUpArrow = FALSE;\r
1333 }\r
1334 } else {\r
1335 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1336 //\r
1337 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1338 //\r
1339 TopOptionIndex++;\r
1340 ShowUpArrow = TRUE;\r
1341 }\r
1342\r
1343 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1344 ShowDownArrow = FALSE;\r
1345 }\r
1346 }\r
1347\r
1348 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1349 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1350 Index++\r
1351 ) {\r
1352 if (MenuOption->Tags[Index].Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1353 continue;\r
1354 }\r
1355\r
1356 if (Key.UnicodeChar == '+') {\r
1357 TempIndex = Index - 1;\r
1358 } else {\r
1359 TempIndex = Index + 1;\r
1360 }\r
1361 //\r
1362 // Is this the current tag we are on?\r
1363 //\r
1364 if (MenuOption->Tags[Index].Value == TempValue) {\r
1365 //\r
1366 // Is this prior tag a valid choice? If not, bail out\r
1367 //\r
1368 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1369 //\r
1370 // Copy the destination tag to the local variable\r
1371 //\r
1372 CopyMem (&TagBackup, &MenuOption->Tags[TempIndex], sizeof (EFI_TAG));\r
1373 //\r
1374 // Copy the current tag to the tag location before us\r
1375 //\r
1376 CopyMem (&MenuOption->Tags[TempIndex], &MenuOption->Tags[Index], sizeof (EFI_TAG));\r
1377 //\r
1378 // Copy the backed up tag to the current location\r
1379 //\r
1380 CopyMem (&MenuOption->Tags[Index], &TagBackup, sizeof (EFI_TAG));\r
1381\r
1382 //\r
1383 // Adjust the array of values\r
1384 //\r
1385 for (Index = 0; Index < ValueCount; Index++) {\r
1386 if (ValueArrayBackup[Index] == (UINT8) TempValue) {\r
1387 if (Key.UnicodeChar == '+') {\r
1388 if (Index == 0) {\r
1389 //\r
1390 // It is the top of the array already\r
1391 //\r
1392 break;\r
1393 }\r
1394\r
1395 TempIndex = Index - 1;\r
1396 } else {\r
1397 if ((Index + 1) == ValueCount) {\r
1398 //\r
1399 // It is the bottom of the array already\r
1400 //\r
1401 break;\r
1402 }\r
1403\r
1404 TempIndex = Index + 1;\r
1405 }\r
1406\r
1407 ValueBackup = ValueArrayBackup[TempIndex];\r
1408 ValueArrayBackup[TempIndex] = ValueArrayBackup[Index];\r
1409 ValueArrayBackup[Index] = ValueBackup;\r
1410 Initialized = TRUE;\r
1411 break;\r
1412 }\r
1413 }\r
1414 break;\r
1415 } else {\r
1416 break;\r
1417 }\r
1418 }\r
1419 }\r
1420 }\r
1421 break;\r
1422\r
1423 case CHAR_NULL:\r
1424 switch (Key.ScanCode) {\r
1425 case SCAN_UP:\r
1426 case SCAN_DOWN:\r
1427 if (Key.ScanCode == SCAN_UP) {\r
1428 if ((TopOptionIndex > 1) && (HighlightPosition == (Top + 1))) {\r
1429 //\r
1430 // Highlight reaches the top of the popup window, scroll one menu item.\r
1431 //\r
1432 TopOptionIndex--;\r
1433 ShowDownArrow = TRUE;\r
1434 }\r
1435\r
1436 if (TopOptionIndex == 1) {\r
1437 ShowUpArrow = FALSE;\r
1438 }\r
1439 } else {\r
1440 if (((TopOptionIndex + MenuLinesInView) <= PopUpMenuLines) && (HighlightPosition == (Bottom - 1))) {\r
1441 //\r
1442 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1443 //\r
1444 TopOptionIndex++;\r
1445 ShowUpArrow = TRUE;\r
1446 }\r
1447\r
1448 if ((TopOptionIndex + MenuLinesInView) == (PopUpMenuLines + 1)) {\r
1449 ShowDownArrow = FALSE;\r
1450 }\r
1451 }\r
1452\r
1453 for (Index = MenuOption->TagIndex + TopOptionIndex;\r
1454 MenuOption->Tags[Index].Operand != EFI_IFR_END_ONE_OF_OP;\r
1455 Index++\r
1456 ) {\r
1457 if (MenuOption->Tags[Index].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1458 if (Initialized) {\r
1459 for (Index = 0; (ValueArrayBackup[Index] != TempValue) && (Index < ValueCount); Index++)\r
1460 ;\r
1461\r
1462 //\r
1463 // Did we hit the end of the array? Either get the first TempValue or the next one\r
1464 //\r
1465 if (Key.ScanCode == SCAN_UP) {\r
1466 if (Index == 0) {\r
1467 TempValue = ValueArrayBackup[0];\r
1468 } else {\r
1469 TempValue = ValueArrayBackup[Index - 1];\r
1470 }\r
1471 } else {\r
1472 if ((Index + 1) == ValueCount) {\r
1473 TempValue = ValueArrayBackup[Index];\r
1474 } else {\r
1475 TempValue = ValueArrayBackup[Index + 1];\r
1476 }\r
1477 }\r
1478 break;\r
1479 } else {\r
1480 if (Key.ScanCode == SCAN_UP) {\r
1481 TempIndex = Index - 1;\r
1482 \r
1483 //\r
1484 // Keep going until meets meaningful tag.\r
1485 //\r
1486 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1487 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1488 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1489 ||\r
1490 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1491 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1492 TempIndex--;\r
1493 }\r
1494 } else {\r
1495 TempIndex = Index + 1;\r
1496\r
1497 //\r
1498 // Keep going until meets meaningful tag.\r
1499 //\r
1500 while ((MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OPTION_OP &&\r
1501 MenuOption->Tags[TempIndex].Operand != EFI_IFR_ONE_OF_OP &&\r
1502 MenuOption->Tags[TempIndex].Operand != EFI_IFR_END_ONE_OF_OP)\r
1503 ||\r
1504 (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP &&\r
1505 (MenuOption->Tags[TempIndex].Suppress || MenuOption->Tags[TempIndex].GrayOut))) {\r
1506 TempIndex++;\r
1507 }\r
1508 }\r
1509 //\r
1510 // The option value is the same as what is stored in NV store. This is where we take action\r
1511 //\r
1512 if (MenuOption->Tags[Index].Value == TempValue) {\r
1513 //\r
1514 // Only if the previous op-code is an option can we select it, otherwise we are at the left-most option\r
1515 //\r
1516 if (MenuOption->Tags[TempIndex].Operand == EFI_IFR_ONE_OF_OPTION_OP) {\r
1517 TempValue = MenuOption->Tags[TempIndex].Value;\r
1518 *KeyValue = MenuOption->Tags[TempIndex].Key;\r
1519 } else {\r
1520 TempValue = MenuOption->Tags[Index].Value;\r
1521 *KeyValue = MenuOption->Tags[Index].Key;\r
1522 }\r
1523 break;\r
1524 }\r
1525 }\r
1526 }\r
1527 }\r
1528 break;\r
1529\r
1530 case SCAN_ESC:\r
1531 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1532 if (ValueArrayBackup != NULL) {\r
1533 gBS->FreePool (ValueArrayBackup);\r
1534 }\r
1535\r
1536 return EFI_DEVICE_ERROR;\r
1537\r
1538 default:\r
1539 break;\r
1540 }\r
1541\r
1542 break;\r
1543\r
1544 case CHAR_CARRIAGE_RETURN:\r
1545 //\r
1546 // return the current selection\r
1547 //\r
1548 if (Tag->Operand == EFI_IFR_ORDERED_LIST_OP) {\r
1549 CopyMem (ValueArray, ValueArrayBackup, ValueCount);\r
1550 gBS->FreePool (ValueArrayBackup);\r
1551 } else {\r
1552 *Value = TempValue;\r
1553 }\r
1554\r
1555 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1556 return EFI_SUCCESS;\r
1557\r
1558 default:\r
1559 break;\r
1560 }\r
1561 } while (1);\r
1562\r
1563 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1564 return EFI_SUCCESS;\r
1565}\r
1566\r
1567EFI_STATUS\r
1568WaitForKeyStroke (\r
1569 OUT EFI_INPUT_KEY *Key\r
1570 )\r
1571{\r
1572 EFI_STATUS Status;\r
1573\r
1574 do {\r
1575 UiWaitForSingleEvent (gST->ConIn->WaitForKey, 0);\r
1576 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, Key);\r
1577 } while (EFI_ERROR(Status));\r
1578\r
1579 return Status;\r
1580}\r