]> code.delx.au - refind/blobdiff - refind/menu.c
install.sh & related: Improved Secure Boot detection & removed error
[refind] / refind / menu.c
index ebe7cae714e3d562c6914940a9c8eb55b5eda4d1..e55bcf45529415a374aea84af2e72d318b93c04c 100644 (file)
@@ -361,12 +361,12 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
     UINTN index;
     INTN ShortcutEntry;
     BOOLEAN HaveTimeout = FALSE;
+    BOOLEAN WaitForRelease = FALSE;
     UINTN TimeoutCountdown = 0;
     INTN PreviousTime = -1, CurrentTime, TimeSinceKeystroke = 0;
     CHAR16 TimeoutMessage[256];
     CHAR16 KeyAsString[2];
     UINTN MenuExit;
-//     EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 };
 
     if (Screen->TimeoutSeconds > 0) {
         HaveTimeout = TRUE;
@@ -382,6 +382,25 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
         if (GlobalConfig.ScreensaverTime != -1)
            UpdateScroll(&State, SCROLL_NONE);
     }
+
+    if (Screen->TimeoutSeconds == -1) {
+        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+        if (Status == EFI_NOT_READY) {
+            MenuExit = MENU_EXIT_TIMEOUT;
+        } else {
+            KeyAsString[0] = key.UnicodeChar;
+            KeyAsString[1] = 0;
+            ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString);
+            if (ShortcutEntry >= 0) {
+                State.CurrentSelection = ShortcutEntry;
+                MenuExit = MENU_EXIT_ENTER;
+            } else {
+                WaitForRelease = TRUE;
+                HaveTimeout = FALSE;
+            }
+        }
+    }
+
     if (GlobalConfig.ScreensaverTime != -1)
         State.PaintAll = TRUE;
 
@@ -395,6 +414,19 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
             State.PaintSelection = FALSE;
         }
 
+        if (WaitForRelease) {
+            Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+            if (Status == EFI_SUCCESS) {
+                // reset, because otherwise the buffer gets queued with keystrokes
+                refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, FALSE);
+                refit_call1_wrapper(BS->Stall, 100000);
+            } else {
+                WaitForRelease = FALSE;
+                refit_call2_wrapper(ST->ConIn->Reset, ST->ConIn, TRUE);
+            }
+            continue;
+        }
+
         if (HaveTimeout) {
             CurrentTime = (TimeoutCountdown + 5) / 10;
             if (CurrentTime != PreviousTime) {
@@ -412,18 +444,39 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
                 // timeout expired
                 MenuExit = MENU_EXIT_TIMEOUT;
                 break;
-            } else if (HaveTimeout) {
-                refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
-                TimeoutCountdown--;
-                TimeSinceKeystroke++;
-            } else if (GlobalConfig.ScreensaverTime > 0) {
-                refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
-                TimeSinceKeystroke++;
-                if (TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10)) {
-                   SaveScreen();
-                   State.PaintAll = TRUE;
-                   TimeSinceKeystroke = 0;
-                } // if
+            } else if (HaveTimeout || GlobalConfig.ScreensaverTime > 0) {
+               EFI_EVENT           TimerEvent;
+               UINTN               ElapsCount = 1;
+
+               Status = refit_call5_wrapper(BS->CreateEvent, EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+               if (EFI_ERROR(Status)) {
+                   refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
+               } else {
+                   EFI_EVENT           WaitList[2];
+                   UINTN               Index;
+
+                   refit_call3_wrapper(BS->SetTimer, TimerEvent, TimerRelative, 10000000); // 1s Timeout
+                   WaitList[0] = ST->ConIn->WaitForKey;
+                   WaitList[1] = TimerEvent;
+                   Status = refit_call3_wrapper(BS->WaitForEvent, 2, WaitList, &Index);
+                   refit_call1_wrapper(BS->CloseEvent, TimerEvent);
+                   if (EFI_ERROR(Status))
+                       refit_call1_wrapper(BS->Stall, 100000); // Pause for 100 ms
+                   else if(Index == 0)
+                       continue;
+                   else
+                       ElapsCount = 10; // always counted as 1s to end of the timeout
+               }
+               TimeSinceKeystroke += ElapsCount;
+               if(HaveTimeout) {
+                   TimeoutCountdown = TimeoutCountdown <= ElapsCount ? 0 : TimeoutCountdown - ElapsCount;
+               } else if (GlobalConfig.ScreensaverTime > 0 &&
+                       TimeSinceKeystroke > (GlobalConfig.ScreensaverTime * 10))
+               {
+                       SaveScreen();
+                       State.PaintAll = TRUE;
+                       TimeSinceKeystroke = 0;
+               } // if
             } else {
                 refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
             }
@@ -980,7 +1033,7 @@ static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State,
 } // static VOID MoveSelection(VOID)
 
 // Display a 48x48 icon at the specified location. Uses the image specified by
-// ExternalFilename if it's available, or BuiltInImage if it's not. The 
+// ExternalFilename if it's available, or BuiltInImage if it's not. The
 // Y position is specified as the center value, and so is adjusted by half
 // the icon's height. The X position is set along the icon's left
 // edge if Alignment == ALIGN_LEFT, and along the right edge if