]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/DisplayEngineDxe/InputHandler.c
MdeModulePkg: Update FirmwarePerformanceDataTableDxe for LegacyBoot
[mirror_edk2.git] / MdeModulePkg / Universal / DisplayEngineDxe / InputHandler.c
CommitLineData
7c6c064c
ED
1/** @file\r
2Implementation for handling user input from the User Interfaces.\r
3\r
4Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "FormDisplay.h"\r
16\r
17/**\r
18 Get maximum and minimum info from this opcode.\r
19\r
20 @param OpCode Pointer to the current input opcode.\r
21 @param Minimum The minimum size info for this opcode.\r
22 @param Maximum The maximum size info for this opcode.\r
23\r
24**/\r
25VOID\r
26GetFieldFromOp (\r
27 IN EFI_IFR_OP_HEADER *OpCode,\r
28 OUT UINTN *Minimum,\r
29 OUT UINTN *Maximum\r
30 )\r
31{\r
32 EFI_IFR_STRING *StringOp;\r
33 EFI_IFR_PASSWORD *PasswordOp;\r
34 if (OpCode->OpCode == EFI_IFR_STRING_OP) {\r
35 StringOp = (EFI_IFR_STRING *) OpCode;\r
36 *Minimum = StringOp->MinSize;\r
37 *Maximum = StringOp->MaxSize; \r
38 } else if (OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
39 PasswordOp = (EFI_IFR_PASSWORD *) OpCode;\r
40 *Minimum = PasswordOp->MinSize;\r
41 *Maximum = PasswordOp->MaxSize; \r
42 } else {\r
43 *Minimum = 0;\r
44 *Maximum = 0; \r
45 }\r
46}\r
47\r
48/**\r
49 Get string or password input from user.\r
50\r
51 @param MenuOption Pointer to the current input menu.\r
52 @param Prompt The prompt string shown on popup window.\r
53 @param StringPtr Old user input and destination for use input string.\r
54\r
55 @retval EFI_SUCCESS If string input is read successfully\r
56 @retval EFI_DEVICE_ERROR If operation fails\r
57\r
58**/\r
59EFI_STATUS\r
60ReadString (\r
61 IN UI_MENU_OPTION *MenuOption,\r
62 IN CHAR16 *Prompt,\r
63 IN OUT CHAR16 *StringPtr\r
64 )\r
65{\r
66 EFI_STATUS Status;\r
67 EFI_INPUT_KEY Key;\r
68 CHAR16 NullCharacter;\r
69 UINTN ScreenSize;\r
70 CHAR16 Space[2];\r
71 CHAR16 KeyPad[2];\r
72 CHAR16 *TempString;\r
73 CHAR16 *BufferedString;\r
74 UINTN Index;\r
75 UINTN Index2;\r
76 UINTN Count;\r
77 UINTN Start;\r
78 UINTN Top;\r
79 UINTN DimensionsWidth;\r
80 UINTN DimensionsHeight;\r
81 UINTN CurrentCursor;\r
82 BOOLEAN CursorVisible;\r
83 UINTN Minimum;\r
84 UINTN Maximum;\r
85 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
86 BOOLEAN IsPassword;\r
87\r
88 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
89 DimensionsHeight = gStatementDimensions.BottomRow - gStatementDimensions.TopRow;\r
90\r
91 NullCharacter = CHAR_NULL;\r
92 ScreenSize = GetStringWidth (Prompt) / sizeof (CHAR16);\r
93 Space[0] = L' ';\r
94 Space[1] = CHAR_NULL;\r
95\r
96 Question = MenuOption->ThisTag;\r
97 GetFieldFromOp(Question->OpCode, &Minimum, &Maximum);\r
98\r
99 if (Question->OpCode->OpCode == EFI_IFR_PASSWORD_OP) {\r
100 IsPassword = TRUE;\r
101 } else {\r
102 IsPassword = FALSE;\r
103 }\r
104\r
105 TempString = AllocateZeroPool ((Maximum + 1)* sizeof (CHAR16));\r
106 ASSERT (TempString);\r
107\r
108 if (ScreenSize < (Maximum + 1)) {\r
109 ScreenSize = Maximum + 1;\r
110 }\r
111\r
112 if ((ScreenSize + 2) > DimensionsWidth) {\r
113 ScreenSize = DimensionsWidth - 2;\r
114 }\r
115\r
116 BufferedString = AllocateZeroPool (ScreenSize * 2);\r
117 ASSERT (BufferedString);\r
118\r
119 Start = (DimensionsWidth - ScreenSize - 2) / 2 + gStatementDimensions.LeftColumn + 1;\r
120 Top = ((DimensionsHeight - 6) / 2) + gStatementDimensions.TopRow - 1;\r
121\r
122 //\r
123 // Display prompt for string\r
124 //\r
125 // CreateDialog (NULL, "", Prompt, Space, "", NULL);\r
126 CreateMultiStringPopUp (ScreenSize, 4, &NullCharacter, Prompt, Space, &NullCharacter);\r
127 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
128\r
129 CursorVisible = gST->ConOut->Mode->CursorVisible;\r
130 gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
131\r
132 CurrentCursor = GetStringWidth (StringPtr) / 2 - 1;\r
133 if (CurrentCursor != 0) {\r
134 //\r
135 // Show the string which has beed saved before.\r
136 //\r
137 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
138 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
139\r
140 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
141 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
142 } else {\r
143 Index = 0;\r
144 }\r
145\r
146 if (IsPassword) {\r
147 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
148 }\r
149\r
150 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
151 BufferedString[Count] = StringPtr[Index];\r
152\r
153 if (IsPassword) {\r
154 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
155 }\r
156 }\r
157\r
158 if (!IsPassword) {\r
159 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
160 }\r
161 \r
162 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
163 gST->ConOut->SetCursorPosition (gST->ConOut, Start + GetStringWidth (StringPtr) / 2, Top + 3);\r
164 }\r
165 \r
166 do {\r
167 Status = WaitForKeyStroke (&Key);\r
168 ASSERT_EFI_ERROR (Status);\r
169\r
170 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
171 switch (Key.UnicodeChar) {\r
172 case CHAR_NULL:\r
173 switch (Key.ScanCode) {\r
174 case SCAN_LEFT:\r
175 if (CurrentCursor > 0) {\r
176 CurrentCursor--;\r
177 }\r
178 break;\r
179\r
180 case SCAN_RIGHT:\r
181 if (CurrentCursor < (GetStringWidth (StringPtr) / 2 - 1)) {\r
182 CurrentCursor++;\r
183 }\r
184 break;\r
185\r
186 case SCAN_ESC:\r
187 FreePool (TempString);\r
188 FreePool (BufferedString);\r
189 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
190 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
191 return EFI_DEVICE_ERROR;\r
192\r
193 default:\r
194 break;\r
195 }\r
196\r
197 break;\r
198\r
199 case CHAR_CARRIAGE_RETURN:\r
200 if (GetStringWidth (StringPtr) >= ((Minimum + 1) * sizeof (CHAR16))) {\r
201\r
202 FreePool (TempString);\r
203 FreePool (BufferedString);\r
204 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
205 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
206 return EFI_SUCCESS;\r
207 } else {\r
208 //\r
209 // Simply create a popup to tell the user that they had typed in too few characters.\r
210 // To save code space, we can then treat this as an error and return back to the menu.\r
211 //\r
212 do {\r
213 CreateDialog (&Key, &NullCharacter, gMiniString, gPressEnter, &NullCharacter, NULL);\r
214 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
215\r
216 FreePool (TempString);\r
217 FreePool (BufferedString);\r
218 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
219 gST->ConOut->EnableCursor (gST->ConOut, CursorVisible);\r
220 return EFI_DEVICE_ERROR;\r
221 }\r
222\r
223 break;\r
224\r
225 case CHAR_BACKSPACE:\r
226 if (StringPtr[0] != CHAR_NULL && CurrentCursor != 0) {\r
227 for (Index = 0; Index < CurrentCursor - 1; Index++) {\r
228 TempString[Index] = StringPtr[Index];\r
229 }\r
230 Count = GetStringWidth (StringPtr) / 2 - 1;\r
231 if (Count >= CurrentCursor) {\r
232 for (Index = CurrentCursor - 1, Index2 = CurrentCursor; Index2 < Count; Index++, Index2++) {\r
233 TempString[Index] = StringPtr[Index2];\r
234 }\r
235 TempString[Index] = CHAR_NULL;\r
236 }\r
237 //\r
238 // Effectively truncate string by 1 character\r
239 //\r
240 StrCpy (StringPtr, TempString);\r
241 CurrentCursor --;\r
242 }\r
243\r
244 default:\r
245 //\r
246 // If it is the beginning of the string, don't worry about checking maximum limits\r
247 //\r
248 if ((StringPtr[0] == CHAR_NULL) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
249 StrnCpy (StringPtr, &Key.UnicodeChar, 1);\r
250 CurrentCursor++;\r
251 } else if ((GetStringWidth (StringPtr) < ((Maximum + 1) * sizeof (CHAR16))) && (Key.UnicodeChar != CHAR_BACKSPACE)) {\r
252 KeyPad[0] = Key.UnicodeChar;\r
253 KeyPad[1] = CHAR_NULL;\r
254 Count = GetStringWidth (StringPtr) / 2 - 1;\r
255 if (CurrentCursor < Count) {\r
256 for (Index = 0; Index < CurrentCursor; Index++) {\r
257 TempString[Index] = StringPtr[Index];\r
258 }\r
259 TempString[Index] = CHAR_NULL;\r
260 StrCat (TempString, KeyPad);\r
261 StrCat (TempString, StringPtr + CurrentCursor);\r
262 StrCpy (StringPtr, TempString);\r
263 } else {\r
264 StrCat (StringPtr, KeyPad);\r
265 }\r
266 CurrentCursor++;\r
267 }\r
268\r
269 //\r
270 // If the width of the input string is now larger than the screen, we nee to\r
271 // adjust the index to start printing portions of the string\r
272 //\r
273 SetUnicodeMem (BufferedString, ScreenSize - 1, L' ');\r
274 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
275\r
276 if ((GetStringWidth (StringPtr) / 2) > (DimensionsWidth - 2)) {\r
277 Index = (GetStringWidth (StringPtr) / 2) - DimensionsWidth + 2;\r
278 } else {\r
279 Index = 0;\r
280 }\r
281\r
282 if (IsPassword) {\r
283 gST->ConOut->SetCursorPosition (gST->ConOut, Start + 1, Top + 3);\r
284 }\r
285\r
286 for (Count = 0; Index + 1 < GetStringWidth (StringPtr) / 2; Index++, Count++) {\r
287 BufferedString[Count] = StringPtr[Index];\r
288\r
289 if (IsPassword) {\r
290 PrintCharAt ((UINTN)-1, (UINTN)-1, L'*');\r
291 }\r
292 }\r
293\r
294 if (!IsPassword) {\r
295 PrintStringAt (Start + 1, Top + 3, BufferedString);\r
296 }\r
297 break;\r
298 }\r
299\r
300 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
301 gST->ConOut->SetCursorPosition (gST->ConOut, Start + CurrentCursor + 1, Top + 3);\r
302 } while (TRUE);\r
303\r
304}\r
305\r
306/**\r
307 Adjust the value to the correct one. Rules follow the sample:\r
308 like: Year change: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
309 Month change: 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
310\r
311 @param QuestionValue Pointer to current question.\r
312 @param Sequence The sequence of the field in the question.\r
313**/\r
314VOID\r
315AdjustQuestionValue (\r
316 IN EFI_HII_VALUE *QuestionValue,\r
317 IN UINT8 Sequence\r
318 )\r
319{\r
320 UINT8 Month;\r
321 UINT16 Year;\r
322 UINT8 Maximum;\r
323 UINT8 Minimum;\r
324\r
325 Month = QuestionValue->Value.date.Month;\r
326 Year = QuestionValue->Value.date.Year;\r
327 Minimum = 1;\r
328\r
329 switch (Month) {\r
330 case 2:\r
331 if ((Year % 4) == 0 && ((Year % 100) != 0 || (Year % 400) == 0)) {\r
332 Maximum = 29;\r
333 } else {\r
334 Maximum = 28;\r
335 }\r
336 break;\r
337 case 4:\r
338 case 6:\r
339 case 9:\r
340 case 11:\r
341 Maximum = 30;\r
342 break;\r
343 default:\r
344 Maximum = 31;\r
345 break;\r
346 }\r
347\r
348 //\r
349 // Change the month area.\r
350 //\r
351 if (Sequence == 0) {\r
352 if (QuestionValue->Value.date.Day > Maximum) {\r
353 QuestionValue->Value.date.Day = Maximum;\r
354 }\r
355 }\r
356 \r
357 //\r
358 // Change the Year area.\r
359 //\r
360 if (Sequence == 2) {\r
361 if (QuestionValue->Value.date.Day > Maximum) {\r
362 QuestionValue->Value.date.Day = Minimum;\r
363 }\r
364 }\r
365}\r
366\r
367/**\r
368 Get field info from numeric opcode.\r
369\r
370 @param OpCode Pointer to the current input opcode.\r
afc9bf79
ED
371 @param IntInput Whether question shows with EFI_IFR_DISPLAY_INT_DEC type.\r
372 @param QuestionValue Input question value, with EFI_HII_VALUE type.\r
373 @param Value Return question value, always return UINT64 type.\r
7c6c064c
ED
374 @param Minimum The minimum size info for this opcode.\r
375 @param Maximum The maximum size info for this opcode.\r
376 @param Step The step size info for this opcode.\r
377 @param StorageWidth The storage width info for this opcode.\r
378\r
379**/\r
380VOID\r
381GetValueFromNum (\r
382 IN EFI_IFR_OP_HEADER *OpCode,\r
afc9bf79
ED
383 IN BOOLEAN IntInput,\r
384 IN EFI_HII_VALUE *QuestionValue,\r
385 OUT UINT64 *Value,\r
7c6c064c
ED
386 OUT UINT64 *Minimum,\r
387 OUT UINT64 *Maximum,\r
388 OUT UINT64 *Step,\r
389 OUT UINT16 *StorageWidth\r
390)\r
391{\r
392 EFI_IFR_NUMERIC *NumericOp;\r
393\r
394 NumericOp = (EFI_IFR_NUMERIC *) OpCode;\r
395 \r
396 switch (NumericOp->Flags & EFI_IFR_NUMERIC_SIZE) {\r
397 case EFI_IFR_NUMERIC_SIZE_1:\r
afc9bf79
ED
398 if (IntInput) {\r
399 *Minimum = (INT64) (INT8) NumericOp->data.u8.MinValue;\r
400 *Maximum = (INT64) (INT8) NumericOp->data.u8.MaxValue;\r
401 *Value = (INT64) (INT8) QuestionValue->Value.u8;\r
402 } else {\r
403 *Minimum = NumericOp->data.u8.MinValue;\r
404 *Maximum = NumericOp->data.u8.MaxValue;\r
405 *Value = QuestionValue->Value.u8;\r
406 }\r
7c6c064c
ED
407 *Step = NumericOp->data.u8.Step;\r
408 *StorageWidth = (UINT16) sizeof (UINT8);\r
409 break;\r
410 \r
411 case EFI_IFR_NUMERIC_SIZE_2:\r
afc9bf79
ED
412 if (IntInput) {\r
413 *Minimum = (INT64) (INT16) NumericOp->data.u16.MinValue;\r
414 *Maximum = (INT64) (INT16) NumericOp->data.u16.MaxValue;\r
415 *Value = (INT64) (INT16) QuestionValue->Value.u16;\r
416 } else {\r
417 *Minimum = NumericOp->data.u16.MinValue;\r
418 *Maximum = NumericOp->data.u16.MaxValue;\r
419 *Value = QuestionValue->Value.u16;\r
420 }\r
7c6c064c
ED
421 *Step = NumericOp->data.u16.Step;\r
422 *StorageWidth = (UINT16) sizeof (UINT16);\r
423 break;\r
424 \r
425 case EFI_IFR_NUMERIC_SIZE_4:\r
afc9bf79
ED
426 if (IntInput) {\r
427 *Minimum = (INT64) (INT32) NumericOp->data.u32.MinValue;\r
428 *Maximum = (INT64) (INT32) NumericOp->data.u32.MaxValue;\r
429 *Value = (INT64) (INT32) QuestionValue->Value.u32;\r
430 } else {\r
431 *Minimum = NumericOp->data.u32.MinValue;\r
432 *Maximum = NumericOp->data.u32.MaxValue;\r
433 *Value = QuestionValue->Value.u32;\r
434 }\r
7c6c064c
ED
435 *Step = NumericOp->data.u32.Step;\r
436 *StorageWidth = (UINT16) sizeof (UINT32);\r
437 break;\r
438 \r
439 case EFI_IFR_NUMERIC_SIZE_8:\r
afc9bf79
ED
440 if (IntInput) {\r
441 *Minimum = (INT64) NumericOp->data.u64.MinValue;\r
442 *Maximum = (INT64) NumericOp->data.u64.MaxValue;\r
443 *Value = (INT64) QuestionValue->Value.u64;\r
444 } else {\r
445 *Minimum = NumericOp->data.u64.MinValue;\r
446 *Maximum = NumericOp->data.u64.MaxValue;\r
447 *Value = QuestionValue->Value.u64;\r
448 }\r
7c6c064c
ED
449 *Step = NumericOp->data.u64.Step;\r
450 *StorageWidth = (UINT16) sizeof (UINT64);\r
451 break;\r
452 \r
453 default:\r
454 break;\r
455 }\r
456\r
457 if (*Maximum == 0) {\r
458 *Maximum = (UINT64) -1;\r
459 }\r
460}\r
461\r
462/**\r
463 This routine reads a numeric value from the user input.\r
464\r
465 @param MenuOption Pointer to the current input menu.\r
466\r
467 @retval EFI_SUCCESS If numerical input is read successfully\r
468 @retval EFI_DEVICE_ERROR If operation fails\r
469\r
470**/\r
471EFI_STATUS\r
472GetNumericInput (\r
473 IN UI_MENU_OPTION *MenuOption\r
474 )\r
475{\r
7c6c064c
ED
476 UINTN Column;\r
477 UINTN Row;\r
478 CHAR16 InputText[MAX_NUMERIC_INPUT_WIDTH];\r
479 CHAR16 FormattedNumber[MAX_NUMERIC_INPUT_WIDTH - 1];\r
480 UINT64 PreviousNumber[MAX_NUMERIC_INPUT_WIDTH - 3];\r
481 UINTN Count;\r
482 UINTN Loop;\r
483 BOOLEAN ManualInput;\r
484 BOOLEAN HexInput;\r
afc9bf79
ED
485 BOOLEAN IntInput;\r
486 BOOLEAN Negative;\r
487 BOOLEAN ValidateFail;\r
7c6c064c
ED
488 BOOLEAN DateOrTime;\r
489 UINTN InputWidth;\r
490 UINT64 EditValue;\r
491 UINT64 Step;\r
492 UINT64 Minimum;\r
493 UINT64 Maximum;\r
494 UINTN EraseLen;\r
495 UINT8 Digital;\r
496 EFI_INPUT_KEY Key;\r
497 EFI_HII_VALUE *QuestionValue;\r
498 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
499 EFI_IFR_NUMERIC *NumericOp;\r
500 UINT16 StorageWidth;\r
501\r
502 Column = MenuOption->OptCol;\r
503 Row = MenuOption->Row;\r
504 PreviousNumber[0] = 0;\r
505 Count = 0;\r
506 InputWidth = 0;\r
507 Digital = 0;\r
508 StorageWidth = 0;\r
509 Minimum = 0;\r
510 Maximum = 0;\r
511 NumericOp = NULL;\r
afc9bf79
ED
512 IntInput = FALSE;\r
513 HexInput = FALSE;\r
514 Negative = FALSE;\r
515 ValidateFail = FALSE;\r
7c6c064c
ED
516\r
517 Question = MenuOption->ThisTag;\r
518 QuestionValue = &Question->CurrentValue;\r
519\r
520 //\r
521 // Only two case, user can enter to this function: Enter and +/- case.\r
522 // In Enter case, gDirection = 0; in +/- case, gDirection = SCAN_LEFT/SCAN_WRIGHT\r
523 //\r
524 ManualInput = (BOOLEAN)(gDirection == 0 ? TRUE : FALSE);\r
525\r
526 if ((Question->OpCode->OpCode == EFI_IFR_DATE_OP) || (Question->OpCode->OpCode == EFI_IFR_TIME_OP)) {\r
527 DateOrTime = TRUE;\r
528 } else {\r
529 DateOrTime = FALSE;\r
530 }\r
531\r
532 //\r
533 // Prepare Value to be edit\r
534 //\r
535 EraseLen = 0;\r
536 EditValue = 0;\r
537 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
538 Step = 1;\r
539 Minimum = 1;\r
540\r
541 switch (MenuOption->Sequence) {\r
542 case 0:\r
543 Maximum = 12;\r
544 EraseLen = 4;\r
545 EditValue = QuestionValue->Value.date.Month;\r
546 break;\r
547\r
548 case 1:\r
549 switch (QuestionValue->Value.date.Month) {\r
550 case 2:\r
551 if ((QuestionValue->Value.date.Year % 4) == 0 && \r
552 ((QuestionValue->Value.date.Year % 100) != 0 || \r
553 (QuestionValue->Value.date.Year % 400) == 0)) {\r
554 Maximum = 29;\r
555 } else {\r
556 Maximum = 28;\r
557 }\r
558 break;\r
559 case 4:\r
560 case 6:\r
561 case 9:\r
562 case 11:\r
563 Maximum = 30;\r
564 break;\r
565 default:\r
566 Maximum = 31;\r
567 break;\r
568 } \r
569\r
570 EraseLen = 3;\r
571 EditValue = QuestionValue->Value.date.Day;\r
572 break;\r
573\r
574 case 2:\r
575 Maximum = 0xffff;\r
576 EraseLen = 5;\r
577 EditValue = QuestionValue->Value.date.Year;\r
578 break;\r
579\r
580 default:\r
581 break;\r
582 }\r
583 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
584 Step = 1;\r
585 Minimum = 0;\r
586\r
587 switch (MenuOption->Sequence) {\r
588 case 0:\r
589 Maximum = 23;\r
590 EraseLen = 4;\r
591 EditValue = QuestionValue->Value.time.Hour;\r
592 break;\r
593\r
594 case 1:\r
595 Maximum = 59;\r
596 EraseLen = 3;\r
597 EditValue = QuestionValue->Value.time.Minute;\r
598 break;\r
599\r
600 case 2:\r
601 Maximum = 59;\r
602 EraseLen = 3;\r
603 EditValue = QuestionValue->Value.time.Second;\r
604 break;\r
605\r
606 default:\r
607 break;\r
608 }\r
609 } else {\r
610 ASSERT (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP);\r
611 NumericOp = (EFI_IFR_NUMERIC *) Question->OpCode;\r
afc9bf79 612 GetValueFromNum(Question->OpCode, (NumericOp->Flags & EFI_IFR_DISPLAY) == 0, QuestionValue, &EditValue, &Minimum, &Maximum, &Step, &StorageWidth);\r
7c6c064c
ED
613 EraseLen = gOptionBlockWidth;\r
614 }\r
615\r
afc9bf79
ED
616 if ((Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) && (NumericOp != NULL)) {\r
617 if ((NumericOp->Flags & EFI_IFR_DISPLAY) == EFI_IFR_DISPLAY_UINT_HEX){\r
618 HexInput = TRUE;\r
619 } else if ((NumericOp->Flags & EFI_IFR_DISPLAY) == 0){\r
620 //\r
621 // Display with EFI_IFR_DISPLAY_INT_DEC type. Support negative number.\r
622 //\r
623 IntInput = TRUE;\r
624 }\r
7c6c064c
ED
625 }\r
626\r
627 //\r
628 // Enter from "Enter" input, clear the old word showing.\r
629 //\r
630 if (ManualInput) {\r
631 if (Question->OpCode->OpCode == EFI_IFR_NUMERIC_OP) {\r
632 if (HexInput) {\r
633 InputWidth = StorageWidth * 2;\r
634 } else {\r
635 switch (StorageWidth) {\r
636 case 1:\r
637 InputWidth = 3;\r
638 break;\r
639\r
640 case 2:\r
641 InputWidth = 5;\r
642 break;\r
643\r
644 case 4:\r
645 InputWidth = 10;\r
646 break;\r
647\r
648 case 8:\r
649 InputWidth = 20;\r
650 break;\r
651\r
652 default:\r
653 InputWidth = 0;\r
654 break;\r
655 }\r
afc9bf79
ED
656\r
657 if (IntInput) {\r
658 //\r
659 // Support an extra '-' for negative number.\r
660 //\r
661 InputWidth += 1;\r
662 }\r
7c6c064c
ED
663 }\r
664\r
665 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
666 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
667 ASSERT (InputWidth + 2 < MAX_NUMERIC_INPUT_WIDTH);\r
668 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
669 InputText[InputWidth + 2] = L'\0';\r
670\r
671 PrintStringAt (Column, Row, InputText);\r
672 Column++;\r
673 }\r
674\r
675 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
676 if (MenuOption->Sequence == 2) {\r
677 InputWidth = 4;\r
678 } else {\r
679 InputWidth = 2;\r
680 }\r
681\r
682 if (MenuOption->Sequence == 0) {\r
683 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
684 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
685 } else {\r
686 SetUnicodeMem (InputText, InputWidth, L' ');\r
687 }\r
688\r
689 if (MenuOption->Sequence == 2) {\r
690 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
691 } else {\r
692 InputText[InputWidth + 1] = DATE_SEPARATOR;\r
693 }\r
694 InputText[InputWidth + 2] = L'\0';\r
695\r
696 PrintStringAt (Column, Row, InputText);\r
697 if (MenuOption->Sequence == 0) {\r
698 Column++;\r
699 }\r
700 }\r
701\r
702 if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
703 InputWidth = 2;\r
704\r
705 if (MenuOption->Sequence == 0) {\r
706 InputText[0] = LEFT_NUMERIC_DELIMITER;\r
707 SetUnicodeMem (InputText + 1, InputWidth, L' ');\r
708 } else {\r
709 SetUnicodeMem (InputText, InputWidth, L' ');\r
710 }\r
711\r
712 if (MenuOption->Sequence == 2) {\r
713 InputText[InputWidth + 1] = RIGHT_NUMERIC_DELIMITER;\r
714 } else {\r
715 InputText[InputWidth + 1] = TIME_SEPARATOR;\r
716 }\r
717 InputText[InputWidth + 2] = L'\0';\r
718\r
719 PrintStringAt (Column, Row, InputText);\r
720 if (MenuOption->Sequence == 0) {\r
721 Column++;\r
722 }\r
723 }\r
724 }\r
725\r
726 //\r
727 // First time we enter this handler, we need to check to see if\r
728 // we were passed an increment or decrement directive\r
729 //\r
730 do {\r
731 Key.UnicodeChar = CHAR_NULL;\r
732 if (gDirection != 0) {\r
733 Key.ScanCode = gDirection;\r
734 gDirection = 0;\r
735 goto TheKey2;\r
736 }\r
737\r
831537d6 738 WaitForKeyStroke (&Key);\r
7c6c064c
ED
739\r
740TheKey2:\r
741 switch (Key.UnicodeChar) {\r
742\r
743 case '+':\r
744 case '-':\r
afc9bf79
ED
745 if (ManualInput && IntInput) {\r
746 //\r
747 // In Manual input mode, check whether input the negative flag.\r
748 //\r
749 if (Key.UnicodeChar == '-') {\r
750 if (Negative) {\r
751 break;\r
752 }\r
753 Negative = TRUE;\r
754 PrintCharAt (Column++, Row, Key.UnicodeChar);\r
755 }\r
7c6c064c 756 } else {\r
afc9bf79
ED
757 if (Key.UnicodeChar == '+') {\r
758 Key.ScanCode = SCAN_RIGHT;\r
759 } else {\r
760 Key.ScanCode = SCAN_LEFT;\r
761 }\r
762 Key.UnicodeChar = CHAR_NULL;\r
763 goto TheKey2;\r
7c6c064c 764 }\r
afc9bf79 765 break;\r
7c6c064c
ED
766\r
767 case CHAR_NULL:\r
768 switch (Key.ScanCode) {\r
769 case SCAN_LEFT:\r
770 case SCAN_RIGHT:\r
771 if (DateOrTime && !ManualInput) {\r
772 //\r
773 // By setting this value, we will return back to the caller.\r
774 // We need to do this since an auto-refresh will destroy the adjustment\r
775 // based on what the real-time-clock is showing. So we always commit\r
776 // upon changing the value.\r
777 //\r
778 gDirection = SCAN_DOWN;\r
779 }\r
780\r
781 if ((Step != 0) && !ManualInput) {\r
782 if (Key.ScanCode == SCAN_LEFT) {\r
afc9bf79
ED
783 if (IntInput) {\r
784 if ((INT64) EditValue >= (INT64) Minimum + (INT64) Step) {\r
785 EditValue = EditValue - Step;\r
786 } else if ((INT64) EditValue > (INT64) Minimum){\r
787 EditValue = Minimum;\r
788 } else {\r
789 EditValue = Maximum;\r
790 }\r
7c6c064c 791 } else {\r
afc9bf79
ED
792 if (EditValue >= Minimum + Step) {\r
793 EditValue = EditValue - Step;\r
794 } else if (EditValue > Minimum){\r
795 EditValue = Minimum;\r
796 } else {\r
797 EditValue = Maximum;\r
798 }\r
7c6c064c
ED
799 }\r
800 } else if (Key.ScanCode == SCAN_RIGHT) {\r
afc9bf79
ED
801 if (IntInput) {\r
802 if ((INT64) EditValue + (INT64) Step <= (INT64) Maximum) {\r
803 EditValue = EditValue + Step;\r
804 } else if ((INT64) EditValue < (INT64) Maximum) {\r
805 EditValue = Maximum;\r
806 } else {\r
807 EditValue = Minimum;\r
808 }\r
7c6c064c 809 } else {\r
afc9bf79
ED
810 if (EditValue + Step <= Maximum) {\r
811 EditValue = EditValue + Step;\r
812 } else if (EditValue < Maximum) {\r
813 EditValue = Maximum;\r
814 } else {\r
815 EditValue = Minimum;\r
816 }\r
7c6c064c
ED
817 }\r
818 }\r
819\r
820 ZeroMem (FormattedNumber, 21 * sizeof (CHAR16));\r
821 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
822 if (MenuOption->Sequence == 2) {\r
823 //\r
824 // Year\r
825 //\r
826 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%04d", (UINT16) EditValue);\r
827 } else {\r
828 //\r
829 // Month/Day\r
830 //\r
831 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
832 }\r
833\r
834 if (MenuOption->Sequence == 0) {\r
835 ASSERT (EraseLen >= 2);\r
836 FormattedNumber[EraseLen - 2] = DATE_SEPARATOR;\r
837 } else if (MenuOption->Sequence == 1) {\r
838 ASSERT (EraseLen >= 1);\r
839 FormattedNumber[EraseLen - 1] = DATE_SEPARATOR;\r
840 }\r
841 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
842 UnicodeSPrint (FormattedNumber, 21 * sizeof (CHAR16), L"%02d", (UINT8) EditValue);\r
843\r
844 if (MenuOption->Sequence == 0) {\r
845 ASSERT (EraseLen >= 2);\r
846 FormattedNumber[EraseLen - 2] = TIME_SEPARATOR;\r
847 } else if (MenuOption->Sequence == 1) {\r
848 ASSERT (EraseLen >= 1);\r
849 FormattedNumber[EraseLen - 1] = TIME_SEPARATOR;\r
850 }\r
851 } else {\r
852 QuestionValue->Value.u64 = EditValue;\r
853 PrintFormattedNumber (Question, FormattedNumber, 21 * sizeof (CHAR16));\r
854 }\r
855\r
856 gST->ConOut->SetAttribute (gST->ConOut, GetFieldTextColor ());\r
857 for (Loop = 0; Loop < EraseLen; Loop++) {\r
858 PrintStringAt (MenuOption->OptCol + Loop, MenuOption->Row, L" ");\r
859 }\r
860 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
861\r
862 if (MenuOption->Sequence == 0) {\r
863 PrintCharAt (MenuOption->OptCol, Row, LEFT_NUMERIC_DELIMITER);\r
864 Column = MenuOption->OptCol + 1;\r
865 }\r
866\r
867 PrintStringAt (Column, Row, FormattedNumber);\r
868\r
869 if (!DateOrTime || MenuOption->Sequence == 2) {\r
870 PrintCharAt ((UINTN)-1, (UINTN)-1, RIGHT_NUMERIC_DELIMITER);\r
871 }\r
872 }\r
873\r
874 goto EnterCarriageReturn;\r
875 break;\r
876\r
877 case SCAN_UP:\r
878 case SCAN_DOWN:\r
879 goto EnterCarriageReturn;\r
880\r
881 case SCAN_ESC:\r
882 return EFI_DEVICE_ERROR;\r
883\r
884 default:\r
885 break;\r
886 }\r
887\r
888 break;\r
889\r
890EnterCarriageReturn:\r
891\r
892 case CHAR_CARRIAGE_RETURN:\r
893 //\r
894 // Validate input value with Minimum value.\r
895 //\r
afc9bf79
ED
896 ValidateFail = FALSE;\r
897 if (IntInput) {\r
898 //\r
899 // After user input Enter, need to check whether the input value.\r
900 // If input a negative value, should compare with maximum value. \r
901 // else compare with the minimum value.\r
902 //\r
903 if (Negative) {\r
904 ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;\r
905 } else {\r
906 ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;\r
907 }\r
908\r
909 if (ValidateFail) {\r
910 UpdateStatusBar (INPUT_ERROR, TRUE);\r
911 break;\r
912 }\r
913 } else if (EditValue < Minimum) {\r
7c6c064c
ED
914 UpdateStatusBar (INPUT_ERROR, TRUE);\r
915 break;\r
7c6c064c 916 }\r
afc9bf79
ED
917\r
918 UpdateStatusBar (INPUT_ERROR, FALSE);\r
7c6c064c
ED
919 CopyMem (&gUserInput->InputValue, &Question->CurrentValue, sizeof (EFI_HII_VALUE));\r
920 QuestionValue = &gUserInput->InputValue;\r
921 //\r
922 // Store Edit value back to Question\r
923 //\r
924 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP) {\r
925 switch (MenuOption->Sequence) {\r
926 case 0:\r
927 QuestionValue->Value.date.Month = (UINT8) EditValue;\r
928 break;\r
929\r
930 case 1:\r
931 QuestionValue->Value.date.Day = (UINT8) EditValue;\r
932 break;\r
933\r
934 case 2:\r
935 QuestionValue->Value.date.Year = (UINT16) EditValue;\r
936 break;\r
937\r
938 default:\r
939 break;\r
940 }\r
941 } else if (Question->OpCode->OpCode == EFI_IFR_TIME_OP) {\r
942 switch (MenuOption->Sequence) {\r
943 case 0:\r
944 QuestionValue->Value.time.Hour = (UINT8) EditValue;\r
945 break;\r
946\r
947 case 1:\r
948 QuestionValue->Value.time.Minute = (UINT8) EditValue;\r
949 break;\r
950\r
951 case 2:\r
952 QuestionValue->Value.time.Second = (UINT8) EditValue;\r
953 break;\r
954\r
955 default:\r
956 break;\r
957 }\r
958 } else {\r
959 //\r
960 // Numeric\r
961 //\r
962 QuestionValue->Value.u64 = EditValue;\r
963 }\r
964\r
965 //\r
966 // Adjust the value to the correct one.\r
967 // Sample like: 2012.02.29 -> 2013.02.29 -> 2013.02.01\r
968 // 2013.03.29 -> 2013.02.29 -> 2013.02.28\r
969 //\r
970 if (Question->OpCode->OpCode == EFI_IFR_DATE_OP && \r
971 (MenuOption->Sequence == 0 || MenuOption->Sequence == 2)) {\r
972 AdjustQuestionValue (QuestionValue, (UINT8)MenuOption->Sequence);\r
973 }\r
974\r
bfae1330 975 return EFI_SUCCESS;\r
7c6c064c
ED
976 break;\r
977\r
978 case CHAR_BACKSPACE:\r
979 if (ManualInput) {\r
980 if (Count == 0) {\r
afc9bf79
ED
981 if (Negative) {\r
982 Negative = FALSE;\r
983 Column--;\r
984 PrintStringAt (Column, Row, L" ");\r
985 }\r
7c6c064c
ED
986 break;\r
987 }\r
988 //\r
989 // Remove a character\r
990 //\r
991 EditValue = PreviousNumber[Count - 1];\r
992 UpdateStatusBar (INPUT_ERROR, FALSE);\r
993 Count--;\r
994 Column--;\r
995 PrintStringAt (Column, Row, L" ");\r
996 }\r
997 break;\r
998\r
999 default:\r
1000 if (ManualInput) {\r
1001 if (HexInput) {\r
1002 if ((Key.UnicodeChar >= L'0') && (Key.UnicodeChar <= L'9')) {\r
1003 Digital = (UINT8) (Key.UnicodeChar - L'0');\r
1004 } else if ((Key.UnicodeChar >= L'A') && (Key.UnicodeChar <= L'F')) {\r
1005 Digital = (UINT8) (Key.UnicodeChar - L'A' + 0x0A);\r
1006 } else if ((Key.UnicodeChar >= L'a') && (Key.UnicodeChar <= L'f')) {\r
1007 Digital = (UINT8) (Key.UnicodeChar - L'a' + 0x0A);\r
1008 } else {\r
1009 UpdateStatusBar (INPUT_ERROR, TRUE);\r
1010 break;\r
1011 }\r
1012 } else {\r
1013 if (Key.UnicodeChar > L'9' || Key.UnicodeChar < L'0') {\r
1014 UpdateStatusBar (INPUT_ERROR, TRUE);\r
1015 break;\r
1016 }\r
1017 }\r
1018\r
1019 //\r
1020 // If Count exceed input width, there is no way more is valid\r
1021 //\r
1022 if (Count >= InputWidth) {\r
1023 break;\r
1024 }\r
1025 //\r
1026 // Someone typed something valid!\r
1027 //\r
1028 if (Count != 0) {\r
1029 if (HexInput) {\r
1030 EditValue = LShiftU64 (EditValue, 4) + Digital;\r
afc9bf79
ED
1031 } else if (IntInput && Negative) {\r
1032 //\r
1033 // Save the negative number.\r
1034 //\r
1035 EditValue = ~(MultU64x32 (~(EditValue - 1), 10) + (Key.UnicodeChar - L'0')) + 1;\r
7c6c064c
ED
1036 } else {\r
1037 EditValue = MultU64x32 (EditValue, 10) + (Key.UnicodeChar - L'0');\r
1038 }\r
1039 } else {\r
1040 if (HexInput) {\r
1041 EditValue = Digital;\r
afc9bf79
ED
1042 } else if (IntInput && Negative) {\r
1043 //\r
1044 // Save the negative number.\r
1045 //\r
1046 EditValue = ~(Key.UnicodeChar - L'0') + 1;\r
7c6c064c
ED
1047 } else {\r
1048 EditValue = Key.UnicodeChar - L'0';\r
1049 }\r
1050 }\r
1051\r
afc9bf79
ED
1052 if (IntInput) {\r
1053 ValidateFail = FALSE;\r
1054 //\r
1055 // When user input a new value, should check the current value.\r
1056 // If user input a negative value, should compare it with minimum\r
1057 // value, else compare it with maximum value.\r
1058 //\r
1059 if (Negative) {\r
1060 ValidateFail = (INT64) EditValue < (INT64) Minimum ? TRUE : FALSE;\r
1061 } else {\r
1062 ValidateFail = (INT64) EditValue > (INT64) Maximum ? TRUE : FALSE;\r
1063 }\r
1064\r
1065 if (ValidateFail) {\r
1066 UpdateStatusBar (INPUT_ERROR, TRUE);\r
1067 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
1068 EditValue = PreviousNumber[Count];\r
1069 break;\r
1070 }\r
7c6c064c 1071 } else {\r
afc9bf79
ED
1072 if (EditValue > Maximum) {\r
1073 UpdateStatusBar (INPUT_ERROR, TRUE);\r
1074 ASSERT (Count < sizeof (PreviousNumber) / sizeof (PreviousNumber[0]));\r
1075 EditValue = PreviousNumber[Count];\r
1076 break;\r
1077 }\r
7c6c064c
ED
1078 }\r
1079\r
afc9bf79
ED
1080 UpdateStatusBar (INPUT_ERROR, FALSE);\r
1081\r
7c6c064c
ED
1082 Count++;\r
1083 ASSERT (Count < (sizeof (PreviousNumber) / sizeof (PreviousNumber[0])));\r
1084 PreviousNumber[Count] = EditValue;\r
1085\r
1086 gST->ConOut->SetAttribute (gST->ConOut, GetHighlightTextColor ());\r
1087 PrintCharAt (Column, Row, Key.UnicodeChar);\r
1088 Column++;\r
1089 }\r
1090 break;\r
1091 }\r
1092 } while (TRUE);\r
1093}\r
1094\r
1095/**\r
1096 Adjust option order base on the question value.\r
1097\r
1098 @param Question Pointer to current question.\r
1099 @param PopUpMenuLines The line number of the pop up menu.\r
1100\r
1101 @retval EFI_SUCCESS If Option input is processed successfully\r
1102 @retval EFI_DEVICE_ERROR If operation fails\r
1103\r
1104**/\r
1105EFI_STATUS\r
1106AdjustOptionOrder (\r
1107 IN FORM_DISPLAY_ENGINE_STATEMENT *Question,\r
1108 OUT UINTN *PopUpMenuLines\r
1109 )\r
1110{\r
1111 UINTN Index;\r
1112 EFI_IFR_ORDERED_LIST *OrderList;\r
1113 UINT8 *ValueArray;\r
1114 UINT8 ValueType;\r
1115 LIST_ENTRY *Link;\r
1116 DISPLAY_QUESTION_OPTION *OneOfOption;\r
1117 EFI_HII_VALUE *HiiValueArray;\r
1118\r
1119 Link = GetFirstNode (&Question->OptionListHead);\r
1120 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1121 ValueArray = Question->CurrentValue.Buffer;\r
1122 ValueType = OneOfOption->OptionOpCode->Type;\r
1123 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
1124\r
1125 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
1126 if (GetArrayData (ValueArray, ValueType, Index) == 0) {\r
1127 break;\r
1128 }\r
1129 }\r
1130 \r
1131 *PopUpMenuLines = Index;\r
1132 \r
1133 //\r
1134 // Prepare HiiValue array\r
1135 // \r
1136 HiiValueArray = AllocateZeroPool (*PopUpMenuLines * sizeof (EFI_HII_VALUE));\r
1137 ASSERT (HiiValueArray != NULL);\r
1138\r
1139 for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
1140 HiiValueArray[Index].Type = ValueType;\r
1141 HiiValueArray[Index].Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1142 }\r
1143 \r
1144 for (Index = 0; Index < *PopUpMenuLines; Index++) {\r
1145 OneOfOption = ValueToOption (Question, &HiiValueArray[*PopUpMenuLines - Index - 1]);\r
1146 if (OneOfOption == NULL) {\r
1147 return EFI_NOT_FOUND;\r
1148 }\r
1149 \r
1150 RemoveEntryList (&OneOfOption->Link);\r
1151 \r
1152 //\r
1153 // Insert to head.\r
1154 //\r
1155 InsertHeadList (&Question->OptionListHead, &OneOfOption->Link);\r
1156 }\r
1157 \r
1158 FreePool (HiiValueArray);\r
1159\r
1160 return EFI_SUCCESS;\r
1161}\r
1162\r
1163/**\r
1164 Base on the type to compare the value.\r
1165\r
1166 @param Value1 The first value need to compare.\r
1167 @param Value2 The second value need to compare.\r
1168 @param Type The value type for above two values.\r
1169\r
1170 @retval TRUE The two value are same.\r
1171 @retval FALSE The two value are different.\r
1172\r
1173**/\r
1174BOOLEAN\r
1175IsValuesEqual (\r
1176 IN EFI_IFR_TYPE_VALUE *Value1,\r
1177 IN EFI_IFR_TYPE_VALUE *Value2,\r
1178 IN UINT8 Type\r
1179 )\r
1180{\r
1181 switch (Type) {\r
1182 case EFI_IFR_TYPE_BOOLEAN:\r
1183 case EFI_IFR_TYPE_NUM_SIZE_8:\r
5a9f73bf 1184 return (BOOLEAN) (Value1->u8 == Value2->u8);\r
7c6c064c
ED
1185 \r
1186 case EFI_IFR_TYPE_NUM_SIZE_16:\r
5a9f73bf
ED
1187 return (BOOLEAN) (Value1->u16 == Value2->u16);\r
1188 \r
7c6c064c 1189 case EFI_IFR_TYPE_NUM_SIZE_32:\r
5a9f73bf
ED
1190 return (BOOLEAN) (Value1->u32 == Value2->u32);\r
1191 \r
7c6c064c 1192 case EFI_IFR_TYPE_NUM_SIZE_64:\r
5a9f73bf 1193 return (BOOLEAN) (Value1->u64 == Value2->u64);\r
7c6c064c
ED
1194\r
1195 default:\r
1196 ASSERT (FALSE);\r
1197 return FALSE;\r
1198 }\r
1199}\r
1200\r
1201/**\r
1202 Base on the type to set the value.\r
1203\r
1204 @param Dest The dest value.\r
1205 @param Source The source value.\r
1206 @param Type The value type for above two values.\r
1207\r
1208**/\r
1209VOID\r
1210SetValuesByType (\r
1211 OUT EFI_IFR_TYPE_VALUE *Dest,\r
1212 IN EFI_IFR_TYPE_VALUE *Source,\r
1213 IN UINT8 Type\r
1214 )\r
1215{\r
1216 switch (Type) {\r
1217 case EFI_IFR_TYPE_BOOLEAN:\r
1218 Dest->b = Source->b;\r
1219 break;\r
1220\r
1221 case EFI_IFR_TYPE_NUM_SIZE_8:\r
1222 Dest->u8 = Source->u8;\r
1223 break;\r
1224\r
1225 case EFI_IFR_TYPE_NUM_SIZE_16:\r
1226 Dest->u16 = Source->u16;\r
1227 break;\r
1228\r
1229 case EFI_IFR_TYPE_NUM_SIZE_32:\r
1230 Dest->u32 = Source->u32;\r
1231 break;\r
1232\r
1233 case EFI_IFR_TYPE_NUM_SIZE_64:\r
1234 Dest->u64 = Source->u64;\r
1235 break;\r
1236\r
1237 default:\r
1238 ASSERT (FALSE);\r
1239 break;\r
1240 }\r
1241}\r
1242\r
1243/**\r
1244 Get selection for OneOf and OrderedList (Left/Right will be ignored).\r
1245\r
1246 @param MenuOption Pointer to the current input menu.\r
1247\r
1248 @retval EFI_SUCCESS If Option input is processed successfully\r
1249 @retval EFI_DEVICE_ERROR If operation fails\r
1250\r
1251**/\r
1252EFI_STATUS\r
1253GetSelectionInputPopUp (\r
1254 IN UI_MENU_OPTION *MenuOption\r
1255 )\r
1256{\r
7c6c064c
ED
1257 EFI_INPUT_KEY Key;\r
1258 UINTN Index;\r
1259 CHAR16 *StringPtr;\r
1260 CHAR16 *TempStringPtr;\r
1261 UINTN Index2;\r
1262 UINTN TopOptionIndex;\r
1263 UINTN HighlightOptionIndex;\r
1264 UINTN Start;\r
1265 UINTN End;\r
1266 UINTN Top;\r
1267 UINTN Bottom;\r
1268 UINTN PopUpMenuLines;\r
1269 UINTN MenuLinesInView;\r
1270 UINTN PopUpWidth;\r
1271 CHAR16 Character;\r
1272 INT32 SavedAttribute;\r
1273 BOOLEAN ShowDownArrow;\r
1274 BOOLEAN ShowUpArrow;\r
1275 UINTN DimensionsWidth;\r
1276 LIST_ENTRY *Link;\r
1277 BOOLEAN OrderedList;\r
1278 UINT8 *ValueArray;\r
1279 UINT8 *ReturnValue;\r
1280 UINT8 ValueType;\r
1281 EFI_HII_VALUE HiiValue;\r
1282 DISPLAY_QUESTION_OPTION *OneOfOption;\r
1283 DISPLAY_QUESTION_OPTION *CurrentOption;\r
1284 FORM_DISPLAY_ENGINE_STATEMENT *Question;\r
1285 INTN Result;\r
1286 EFI_IFR_ORDERED_LIST *OrderList;\r
1287\r
1288 DimensionsWidth = gStatementDimensions.RightColumn - gStatementDimensions.LeftColumn;\r
1289\r
1290 ValueArray = NULL;\r
1291 ValueType = 0;\r
1292 CurrentOption = NULL;\r
1293 ShowDownArrow = FALSE;\r
1294 ShowUpArrow = FALSE;\r
1295\r
1296 StringPtr = AllocateZeroPool ((gOptionBlockWidth + 1) * 2);\r
1297 ASSERT (StringPtr);\r
1298\r
1299 ZeroMem (&HiiValue, sizeof (EFI_HII_VALUE));\r
1300\r
1301 Question = MenuOption->ThisTag;\r
1302 if (Question->OpCode->OpCode == EFI_IFR_ORDERED_LIST_OP) {\r
1303 Link = GetFirstNode (&Question->OptionListHead);\r
1304 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1305 ValueArray = Question->CurrentValue.Buffer;\r
1306 ValueType = OneOfOption->OptionOpCode->Type;\r
1307 OrderedList = TRUE;\r
1308 OrderList = (EFI_IFR_ORDERED_LIST *) Question->OpCode;\r
1309 } else {\r
1310 OrderedList = FALSE;\r
1311 OrderList = NULL;\r
1312 }\r
1313\r
1314 //\r
1315 // Calculate Option count\r
1316 //\r
1317 PopUpMenuLines = 0;\r
1318 if (OrderedList) {\r
1319 AdjustOptionOrder(Question, &PopUpMenuLines);\r
1320 } else {\r
1321 Link = GetFirstNode (&Question->OptionListHead);\r
1322 while (!IsNull (&Question->OptionListHead, Link)) {\r
1323 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1324 PopUpMenuLines++;\r
1325 Link = GetNextNode (&Question->OptionListHead, Link);\r
1326 }\r
1327 }\r
1328\r
1329 //\r
1330 // Get the number of one of options present and its size\r
1331 //\r
1332 PopUpWidth = 0;\r
1333 HighlightOptionIndex = 0;\r
1334 Link = GetFirstNode (&Question->OptionListHead);\r
1335 for (Index = 0; Index < PopUpMenuLines; Index++) {\r
1336 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1337\r
1338 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1339 if (StrLen (StringPtr) > PopUpWidth) {\r
1340 PopUpWidth = StrLen (StringPtr);\r
1341 }\r
1342 FreePool (StringPtr);\r
1343 HiiValue.Type = OneOfOption->OptionOpCode->Type;\r
1344 SetValuesByType (&HiiValue.Value, &OneOfOption->OptionOpCode->Value, HiiValue.Type);\r
1345 if (!OrderedList && (CompareHiiValue (&Question->CurrentValue, &HiiValue, &Result, NULL) == EFI_SUCCESS) && (Result == 0)) {\r
1346 //\r
1347 // Find current selected Option for OneOf\r
1348 //\r
1349 HighlightOptionIndex = Index;\r
1350 }\r
1351\r
1352 Link = GetNextNode (&Question->OptionListHead, Link);\r
1353 }\r
1354\r
1355 //\r
1356 // Perform popup menu initialization.\r
1357 //\r
1358 PopUpWidth = PopUpWidth + POPUP_PAD_SPACE_COUNT;\r
1359\r
1360 SavedAttribute = gST->ConOut->Mode->Attribute;\r
1361 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
1362\r
1363 if ((PopUpWidth + POPUP_FRAME_WIDTH) > DimensionsWidth) {\r
1364 PopUpWidth = DimensionsWidth - POPUP_FRAME_WIDTH;\r
1365 }\r
1366\r
1367 Start = (DimensionsWidth - PopUpWidth - POPUP_FRAME_WIDTH) / 2 + gStatementDimensions.LeftColumn;\r
1368 End = Start + PopUpWidth + POPUP_FRAME_WIDTH;\r
1369 Top = gStatementDimensions.TopRow;\r
1370 Bottom = gStatementDimensions.BottomRow - 1;\r
1371\r
1372 MenuLinesInView = Bottom - Top - 1;\r
1373 if (MenuLinesInView >= PopUpMenuLines) {\r
1374 Top = Top + (MenuLinesInView - PopUpMenuLines) / 2;\r
1375 Bottom = Top + PopUpMenuLines + 1;\r
1376 } else {\r
1377 ShowDownArrow = TRUE;\r
1378 }\r
1379\r
1380 if (HighlightOptionIndex > (MenuLinesInView - 1)) {\r
1381 TopOptionIndex = HighlightOptionIndex - MenuLinesInView + 1;\r
1382 } else {\r
1383 TopOptionIndex = 0;\r
1384 }\r
1385\r
1386 do {\r
1387 //\r
1388 // Clear that portion of the screen\r
1389 //\r
1390 ClearLines (Start, End, Top, Bottom, GetPopupColor ());\r
1391\r
1392 //\r
1393 // Draw "One of" pop-up menu\r
1394 //\r
1395 Character = BOXDRAW_DOWN_RIGHT;\r
1396 PrintCharAt (Start, Top, Character);\r
1397 for (Index = Start; Index + 2 < End; Index++) {\r
1398 if ((ShowUpArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1399 Character = GEOMETRICSHAPE_UP_TRIANGLE;\r
1400 } else {\r
1401 Character = BOXDRAW_HORIZONTAL;\r
1402 }\r
1403\r
1404 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
1405 }\r
1406\r
1407 Character = BOXDRAW_DOWN_LEFT;\r
1408 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
1409 Character = BOXDRAW_VERTICAL;\r
1410 for (Index = Top + 1; Index < Bottom; Index++) {\r
1411 PrintCharAt (Start, Index, Character);\r
1412 PrintCharAt (End - 1, Index, Character);\r
1413 }\r
1414\r
1415 //\r
1416 // Move to top Option\r
1417 //\r
1418 Link = GetFirstNode (&Question->OptionListHead);\r
1419 for (Index = 0; Index < TopOptionIndex; Index++) {\r
1420 Link = GetNextNode (&Question->OptionListHead, Link);\r
1421 }\r
1422\r
1423 //\r
1424 // Display the One of options\r
1425 //\r
1426 Index2 = Top + 1;\r
1427 for (Index = TopOptionIndex; (Index < PopUpMenuLines) && (Index2 < Bottom); Index++) {\r
1428 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1429 Link = GetNextNode (&Question->OptionListHead, Link);\r
1430\r
1431 StringPtr = GetToken (OneOfOption->OptionOpCode->Option, gFormData->HiiHandle);\r
1432 ASSERT (StringPtr != NULL);\r
1433 //\r
1434 // If the string occupies multiple lines, truncate it to fit in one line,\r
1435 // and append a "..." for indication.\r
1436 //\r
1437 if (StrLen (StringPtr) > (PopUpWidth - 1)) {\r
1438 TempStringPtr = AllocateZeroPool (sizeof (CHAR16) * (PopUpWidth - 1));\r
1439 ASSERT ( TempStringPtr != NULL );\r
1440 CopyMem (TempStringPtr, StringPtr, (sizeof (CHAR16) * (PopUpWidth - 5)));\r
1441 FreePool (StringPtr);\r
1442 StringPtr = TempStringPtr;\r
1443 StrCat (StringPtr, L"...");\r
1444 }\r
1445\r
1446 if (Index == HighlightOptionIndex) {\r
1447 //\r
1448 // Highlight the selected one\r
1449 //\r
1450 CurrentOption = OneOfOption;\r
1451\r
1452 gST->ConOut->SetAttribute (gST->ConOut, GetPickListColor ());\r
1453 PrintStringAt (Start + 2, Index2, StringPtr);\r
1454 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
1455 } else {\r
1456 gST->ConOut->SetAttribute (gST->ConOut, GetPopupColor ());\r
1457 PrintStringAt (Start + 2, Index2, StringPtr);\r
1458 }\r
1459\r
1460 Index2++;\r
1461 FreePool (StringPtr);\r
1462 }\r
1463\r
1464 Character = BOXDRAW_UP_RIGHT;\r
1465 PrintCharAt (Start, Bottom, Character);\r
1466 for (Index = Start; Index + 2 < End; Index++) {\r
1467 if ((ShowDownArrow) && ((Index + 1) == (Start + End) / 2)) {\r
1468 Character = GEOMETRICSHAPE_DOWN_TRIANGLE;\r
1469 } else {\r
1470 Character = BOXDRAW_HORIZONTAL;\r
1471 }\r
1472\r
1473 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
1474 }\r
1475\r
1476 Character = BOXDRAW_UP_LEFT;\r
1477 PrintCharAt ((UINTN)-1, (UINTN)-1, Character);\r
1478\r
1479 //\r
1480 // Get User selection\r
1481 //\r
1482 Key.UnicodeChar = CHAR_NULL;\r
1483 if ((gDirection == SCAN_UP) || (gDirection == SCAN_DOWN)) {\r
1484 Key.ScanCode = gDirection;\r
1485 gDirection = 0;\r
1486 goto TheKey;\r
1487 }\r
1488\r
831537d6 1489 WaitForKeyStroke (&Key);\r
7c6c064c
ED
1490\r
1491TheKey:\r
1492 switch (Key.UnicodeChar) {\r
1493 case '+':\r
1494 if (OrderedList) {\r
1495 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1496 //\r
1497 // Highlight reaches the top of the popup window, scroll one menu item.\r
1498 //\r
1499 TopOptionIndex--;\r
1500 ShowDownArrow = TRUE;\r
1501 }\r
1502\r
1503 if (TopOptionIndex == 0) {\r
1504 ShowUpArrow = FALSE;\r
1505 }\r
1506\r
1507 if (HighlightOptionIndex > 0) {\r
1508 HighlightOptionIndex--;\r
1509\r
1510 ASSERT (CurrentOption != NULL);\r
1511 SwapListEntries (CurrentOption->Link.BackLink, &CurrentOption->Link);\r
1512 }\r
1513 }\r
1514 break;\r
1515\r
1516 case '-':\r
1517 //\r
1518 // If an ordered list op-code, we will allow for a popup of +/- keys\r
1519 // to create an ordered list of items\r
1520 //\r
1521 if (OrderedList) {\r
1522 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1523 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1524 //\r
1525 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1526 //\r
1527 TopOptionIndex++;\r
1528 ShowUpArrow = TRUE;\r
1529 }\r
1530\r
1531 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1532 ShowDownArrow = FALSE;\r
1533 }\r
1534\r
1535 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1536 HighlightOptionIndex++;\r
1537\r
1538 ASSERT (CurrentOption != NULL);\r
1539 SwapListEntries (&CurrentOption->Link, CurrentOption->Link.ForwardLink);\r
1540 }\r
1541 }\r
1542 break;\r
1543\r
1544 case CHAR_NULL:\r
1545 switch (Key.ScanCode) {\r
1546 case SCAN_UP:\r
1547 case SCAN_DOWN:\r
1548 if (Key.ScanCode == SCAN_UP) {\r
1549 if ((TopOptionIndex > 0) && (TopOptionIndex == HighlightOptionIndex)) {\r
1550 //\r
1551 // Highlight reaches the top of the popup window, scroll one menu item.\r
1552 //\r
1553 TopOptionIndex--;\r
1554 ShowDownArrow = TRUE;\r
1555 }\r
1556\r
1557 if (TopOptionIndex == 0) {\r
1558 ShowUpArrow = FALSE;\r
1559 }\r
1560\r
1561 if (HighlightOptionIndex > 0) {\r
1562 HighlightOptionIndex--;\r
1563 }\r
1564 } else {\r
1565 if (((TopOptionIndex + MenuLinesInView) < PopUpMenuLines) &&\r
1566 (HighlightOptionIndex == (TopOptionIndex + MenuLinesInView - 1))) {\r
1567 //\r
1568 // Highlight reaches the bottom of the popup window, scroll one menu item.\r
1569 //\r
1570 TopOptionIndex++;\r
1571 ShowUpArrow = TRUE;\r
1572 }\r
1573\r
1574 if ((TopOptionIndex + MenuLinesInView) == PopUpMenuLines) {\r
1575 ShowDownArrow = FALSE;\r
1576 }\r
1577\r
1578 if (HighlightOptionIndex < (PopUpMenuLines - 1)) {\r
1579 HighlightOptionIndex++;\r
1580 }\r
1581 }\r
1582 break;\r
1583\r
1584 case SCAN_ESC:\r
1585 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1586\r
1587 //\r
1588 // Restore link list order for orderedlist\r
1589 //\r
1590 if (OrderedList) {\r
1591 HiiValue.Type = ValueType;\r
1592 HiiValue.Value.u64 = 0;\r
1593 for (Index = 0; Index < OrderList->MaxContainers; Index++) {\r
1594 HiiValue.Value.u64 = GetArrayData (ValueArray, ValueType, Index);\r
1595 if (HiiValue.Value.u64 == 0) {\r
1596 break;\r
1597 }\r
1598\r
1599 OneOfOption = ValueToOption (Question, &HiiValue);\r
1600 if (OneOfOption == NULL) {\r
1601 return EFI_NOT_FOUND;\r
1602 }\r
1603\r
1604 RemoveEntryList (&OneOfOption->Link);\r
1605 InsertTailList (&Question->OptionListHead, &OneOfOption->Link);\r
1606 }\r
1607 }\r
1608\r
1609 return EFI_DEVICE_ERROR;\r
1610\r
1611 default:\r
1612 break;\r
1613 }\r
1614\r
1615 break;\r
1616\r
1617 case CHAR_CARRIAGE_RETURN:\r
1618 //\r
1619 // return the current selection\r
1620 //\r
1621 if (OrderedList) {\r
1622 ReturnValue = AllocateZeroPool (Question->CurrentValue.BufferLen);\r
1623 ASSERT (ReturnValue != NULL);\r
1624 Index = 0;\r
1625 Link = GetFirstNode (&Question->OptionListHead);\r
1626 while (!IsNull (&Question->OptionListHead, Link)) {\r
1627 OneOfOption = DISPLAY_QUESTION_OPTION_FROM_LINK (Link);\r
1628 Link = GetNextNode (&Question->OptionListHead, Link);\r
1629\r
1630 SetArrayData (ReturnValue, ValueType, Index, OneOfOption->OptionOpCode->Value.u64);\r
1631\r
1632 Index++;\r
1633 if (Index > OrderList->MaxContainers) {\r
1634 break;\r
1635 }\r
1636 }\r
1637 if (CompareMem (ReturnValue, ValueArray, Question->CurrentValue.BufferLen) == 0) {\r
1638 FreePool (ReturnValue);\r
1639 return EFI_DEVICE_ERROR;\r
1640 } else {\r
1641 gUserInput->InputValue.Buffer = ReturnValue;\r
1642 gUserInput->InputValue.BufferLen = Question->CurrentValue.BufferLen;\r
7c6c064c
ED
1643 }\r
1644 } else {\r
1645 ASSERT (CurrentOption != NULL);\r
1646 gUserInput->InputValue.Type = CurrentOption->OptionOpCode->Type;\r
1647 if (IsValuesEqual (&Question->CurrentValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type)) {\r
1648 return EFI_DEVICE_ERROR;\r
1649 } else {\r
1650 SetValuesByType (&gUserInput->InputValue.Value, &CurrentOption->OptionOpCode->Value, gUserInput->InputValue.Type);\r
7c6c064c
ED
1651 }\r
1652 }\r
1653\r
1654 gST->ConOut->SetAttribute (gST->ConOut, SavedAttribute);\r
1655\r
bfae1330 1656 return EFI_SUCCESS;\r
7c6c064c
ED
1657 \r
1658 default:\r
1659 break;\r
1660 }\r
1661 } while (TRUE);\r
1662\r
1663}\r
1664\r