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