]> code.delx.au - refind/commitdiff
Added touchscreen support
authorCJ Vaughter <cj.vaughter@gmail.com>
Tue, 3 May 2016 16:30:44 +0000 (11:30 -0500)
committerCJ Vaughter <cj.vaughter@gmail.com>
Tue, 3 May 2016 16:30:44 +0000 (11:30 -0500)
OS and tool selection via touch are supported, submenus only press enter
on the currently selected item.

refind/config.c
refind/global.h
refind/menu.c
refind/menu.h

index 658f8ebc818d8bccafc65bf24a9985dc9972b4d6..195317efa9147230f17f883595cffc4b1c3475da 100644 (file)
@@ -761,6 +761,9 @@ VOID ReadConfig(CHAR16 *FileName)
               ReadConfig(TokenList[1]);
            }
 
+        } else if (MyStriCmp(TokenList[0], L"enable_touch")) {
+           GlobalConfig.EnableTouch = HandleBoolean(TokenList, TokenCount);
+                  
         }
 
         FreeTokenLine(&TokenList, &TokenCount);
index ad8e17234239e2b42a9791f86a690b7bfd9423e9..1b2a7f9b901fd0e7f0e2c10defbacf6bec0a6e15 100644 (file)
@@ -333,6 +333,7 @@ typedef struct {
    UINT32_LIST      *CsrValues;
    UINTN            ShowTools[NUM_TOOLS];
    CHAR8            ScanFor[NUM_SCAN_OPTIONS]; // codes of types of loaders for which to scan
+   BOOLEAN                     EnableTouch;
 } REFIT_CONFIG;
 
 // Global variables
index 4fa93b15d576b6ec8ebf94f7ea16cf999db3d995..47f308c55d9a2a5c05df34f77b01d095207a9d65 100644 (file)
@@ -100,6 +100,12 @@ static UINTN TileSizes[2] = { 144, 64 };
 static EG_IMAGE *SelectionImages[2] = { NULL, NULL };
 static EG_PIXEL SelectionBackgroundPixel = { 0xff, 0xff, 0xff, 0 };
 
+//Touch variables
+EFI_ABSOLUTE_POINTER_PROTOCOL *TouchProtocol = NULL;
+EFI_GUID TouchGuid = EFI_ABSOLUTE_POINTER_PROTOCOL_GUID;
+BOOLEAN TouchEnabled = FALSE;
+BOOLEAN TouchActive = FALSE;
+
 //
 // Graphics helper functions
 //
@@ -349,16 +355,22 @@ static VOID IdentifyRows(IN SCROLL_STATE *State, IN REFIT_MENU_SCREEN *Screen) {
       State->MaxVisible = State->FinalRow0 + 1;
 } // static VOID IdentifyRows()
 
-// Blank the screen, wait for a keypress, and restore banner/background.
+// Blank the screen, wait for a keypress or touch event, and restore banner/background.
 // Screen may still require redrawing of text and icons on return.
 // TODO: Support more sophisticated screen savers, such as power-saving
 // mode and dynamic images.
 static VOID SaveScreen(VOID) {
    UINTN index;
    EG_PIXEL Black = { 0x0, 0x0, 0x0, 0 };
-
+   EFI_EVENT WaitList[2] = { ST->ConIn->WaitForKey, NULL };
+   
    egClearScreen(&Black);
-   refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+   if(TouchEnabled) {
+         WaitList[1] = TouchProtocol->WaitForInput;
+      refit_call3_wrapper(BS->WaitForEvent, 2, WaitList, &index);
+   } else {
+      refit_call3_wrapper(BS->WaitForEvent, 1, WaitList, &index);
+   }
    if (AllowGraphicsMode)
       SwitchToGraphicsAndClear();
    ReadAllKeyStrokes();
@@ -382,6 +394,9 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
     CHAR16 TimeoutMessage[256];
     CHAR16 KeyAsString[2];
     UINTN MenuExit;
+       
+       EFI_STATUS TouchStatus = EFI_NOT_READY;
+       EFI_ABSOLUTE_POINTER_STATE *TouchState = NULL;
 
     if (Screen->TimeoutSeconds > 0) {
         HaveTimeout = TRUE;
@@ -452,9 +467,27 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
             }
         }
 
-        // read key press (and wait for it if applicable)
-        Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
-        if (Status != EFI_SUCCESS) {
+        // read key press or touch event (and wait for them if applicable)
+               if(TouchEnabled) {
+                       TouchStatus = refit_call2_wrapper(TouchProtocol->GetState, TouchProtocol, TouchState);
+               }
+               Status = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key);
+               
+               if(Status == EFI_SUCCESS) {
+                       TouchActive = FALSE;
+                       TimeSinceKeystroke = 0;
+               } else if(TouchStatus == EFI_SUCCESS) {
+                       if(StyleFunc != MainMenuStyle) {
+                               // prevent user from getting stuck on submenus
+                               // (the only one currently reachable without a keyboard is the about screen)
+                               MenuExit = MENU_EXIT_ENTER;
+                               break;
+                       }
+                       
+                       TouchActive = TRUE;
+                       TimeSinceKeystroke = 0;
+               } else {
+                       EFI_EVENT WaitList[3] = { ST->ConIn->WaitForKey, NULL, NULL };
             if (HaveTimeout && TimeoutCountdown == 0) {
                 // timeout expired
                 MenuExit = MENU_EXIT_TIMEOUT;
@@ -467,17 +500,23 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
                 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);
+                                       
+                                       if(TouchEnabled) {      
+                                               WaitList[1] = TouchProtocol->WaitForInput;
+                                               WaitList[2] = TimerEvent;
+                                               Status = refit_call3_wrapper(BS->WaitForEvent, 3, WaitList, &Index);
+                                       } else {
+                                               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)
+                    else if(Index == 0 || (TouchEnabled && Index == 1))
                         continue;
                     else
                         ElapsCount = 10; // always counted as 1s to end of the timeout
@@ -493,11 +532,14 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
                         TimeSinceKeystroke = 0;
                 } // if
             } else {
-                refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index);
+                               if(TouchEnabled) {
+                                       WaitList[1] = TouchProtocol->WaitForInput;
+                                       refit_call3_wrapper(BS->WaitForEvent, 2, WaitList, &index);
+                               } else {
+                                       refit_call3_wrapper(BS->WaitForEvent, 1, WaitList, &index);
+                               }
             }
             continue;
-        } else {
-           TimeSinceKeystroke = 0;
         } // if/else !read keystroke
 
         if (HaveTimeout) {
@@ -511,66 +553,85 @@ static UINTN RunGenericMenu(IN REFIT_MENU_SCREEN *Screen, IN MENU_STYLE_FUNC Sty
             }
         }
 
-        // react to key press
-        switch (key.ScanCode) {
-            case SCAN_UP:
-                UpdateScroll(&State, SCROLL_LINE_UP);
-                break;
-            case SCAN_LEFT:
-                UpdateScroll(&State, SCROLL_LINE_LEFT);
-                break;
-            case SCAN_DOWN:
-                UpdateScroll(&State, SCROLL_LINE_DOWN);
-                break;
-            case SCAN_RIGHT:
-                UpdateScroll(&State, SCROLL_LINE_RIGHT);
-                break;
-            case SCAN_HOME:
-                UpdateScroll(&State, SCROLL_FIRST);
-                break;
-            case SCAN_END:
-                UpdateScroll(&State, SCROLL_LAST);
-                break;
-            case SCAN_PAGE_UP:
-                UpdateScroll(&State, SCROLL_PAGE_UP);
-                break;
-            case SCAN_PAGE_DOWN:
-                UpdateScroll(&State, SCROLL_PAGE_DOWN);
-                break;
-            case SCAN_ESC:
-                MenuExit = MENU_EXIT_ESCAPE;
-                break;
-            case SCAN_INSERT:
-            case SCAN_F2:
-                MenuExit = MENU_EXIT_DETAILS;
-                break;
-            case SCAN_F10:
-                egScreenShot();
-                break;
-            case 0x0016: // F12
-               if (EjectMedia())
-                  MenuExit = MENU_EXIT_ESCAPE;
-               break;
-        }
-        switch (key.UnicodeChar) {
-            case CHAR_LINEFEED:
-            case CHAR_CARRIAGE_RETURN:
-            case ' ':
-                MenuExit = MENU_EXIT_ENTER;
-                break;
-            case '+':
-                MenuExit = MENU_EXIT_DETAILS;
-                break;
-            default:
-                KeyAsString[0] = key.UnicodeChar;
-                KeyAsString[1] = 0;
-                ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString);
-                if (ShortcutEntry >= 0) {
-                    State.CurrentSelection = ShortcutEntry;
-                    MenuExit = MENU_EXIT_ENTER;
-                }
-                break;
-        }
+               if(!TouchActive) { // react to key press
+                       switch (key.ScanCode) {
+                               case SCAN_UP:
+                                       UpdateScroll(&State, SCROLL_LINE_UP);
+                                       break;
+                               case SCAN_LEFT:
+                                       UpdateScroll(&State, SCROLL_LINE_LEFT);
+                                       break;
+                               case SCAN_DOWN:
+                                       UpdateScroll(&State, SCROLL_LINE_DOWN);
+                                       break;
+                               case SCAN_RIGHT:
+                                       UpdateScroll(&State, SCROLL_LINE_RIGHT);
+                                       break;
+                               case SCAN_HOME:
+                                       UpdateScroll(&State, SCROLL_FIRST);
+                                       break;
+                               case SCAN_END:
+                                       UpdateScroll(&State, SCROLL_LAST);
+                                       break;
+                               case SCAN_PAGE_UP:
+                                       UpdateScroll(&State, SCROLL_PAGE_UP);
+                                       break;
+                               case SCAN_PAGE_DOWN:
+                                       UpdateScroll(&State, SCROLL_PAGE_DOWN);
+                                       break;
+                               case SCAN_ESC:
+                                       MenuExit = MENU_EXIT_ESCAPE;
+                                       break;
+                               case SCAN_INSERT:
+                               case SCAN_F2:
+                                       MenuExit = MENU_EXIT_DETAILS;
+                                       break;
+                               case SCAN_F10:
+                                       egScreenShot();
+                                       break;
+                               case 0x0016: // F12
+                                  if (EjectMedia())
+                                         MenuExit = MENU_EXIT_ESCAPE;
+                                  break;
+                       }
+                       switch (key.UnicodeChar) {
+                               case CHAR_LINEFEED:
+                               case CHAR_CARRIAGE_RETURN:
+                               case ' ':
+                                       MenuExit = MENU_EXIT_ENTER;
+                                       break;
+                               case '+':
+                                       MenuExit = MENU_EXIT_DETAILS;
+                                       break;
+                               default:
+                                       KeyAsString[0] = key.UnicodeChar;
+                                       KeyAsString[1] = 0;
+                                       ShortcutEntry = FindMenuShortcutEntry(Screen, KeyAsString);
+                                       if (ShortcutEntry >= 0) {
+                                               State.CurrentSelection = ShortcutEntry;
+                                               MenuExit = MENU_EXIT_ENTER;
+                                       }
+                                       break;
+                       }
+               } else { //react to touch event
+                       UINTN Item = FindMainMenuItem(Screen, &State, TouchState->CurrentX, TouchState->CurrentY);
+                       
+                       switch(Item) {
+                               case TOUCH_NO_ITEM:
+                                       //do nothing
+                                       break;
+                               case TOUCH_LEFT_ARROW:
+                                       UpdateScroll(&State, SCROLL_PAGE_UP);
+                                       break;
+                               case TOUCH_RIGHT_ARROW:
+                                       UpdateScroll(&State, SCROLL_PAGE_DOWN);
+                                       break;
+                               default:
+                                       State.CurrentSelection = Item;
+                                       MenuExit = MENU_EXIT_ENTER;
+                                       break;
+                       }
+               }
     }
 
     StyleFunc(Screen, &State, MENU_FUNCTION_CLEANUP, NULL);
@@ -970,7 +1031,8 @@ static VOID DrawMainMenuEntry(REFIT_MENU_ENTRY *Entry, BOOLEAN selected, UINTN X
 {
    EG_IMAGE *Background;
 
-   if (selected) {
+   // don't draw selection image if using touch
+   if (selected && !TouchActive) {
       Background = egCropImage(GlobalConfig.ScreenBackground, XPos, YPos,
                                SelectionImages[Entry->Row]->Width, SelectionImages[Entry->Row]->Height);
       egComposeImage(Background, SelectionImages[Entry->Row], 0, 0);
@@ -1181,6 +1243,83 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT
     }
 } // VOID MainMenuStyle()
 
+// Determines the index of the main menu item at the given coordinates.
+UINTN FindMainMenuItem(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT64 PosX, IN UINT64 PosY)
+{
+       UINTN i;
+    static UINTN row0PosX, row0PosXRunning, row1PosY, row0Loaders;
+    UINTN row0Count, row1Count, row1PosX, row1PosXRunning;
+    static UINTN *itemPosX;
+    static UINTN row0PosY;
+       UINTN itemRow;
+
+       row0Count = 0;
+       row1Count = 0;
+       row0Loaders = 0;
+       for (i = 0; i <= State->MaxIndex; i++) {
+          if (Screen->Entries[i]->Row == 1) {
+                 row1Count++;
+          } else {
+                 row0Loaders++;
+                 if (row0Count < State->MaxVisible)
+                        row0Count++;
+          }
+       }
+       row0PosX = (UGAWidth + TILE_XSPACING - (TileSizes[0] + TILE_XSPACING) * row0Count) >> 1;
+       row0PosY = ComputeRow0PosY();
+       row1PosX = (UGAWidth + TILE_XSPACING - (TileSizes[1] + TILE_XSPACING) * row1Count) >> 1;
+       row1PosY = row0PosY + TileSizes[0] + TILE_YSPACING;
+       
+       if(PosY >= row0PosY && PosY <= row0PosY + TileSizes[0]) {
+               itemRow = 0;
+               if(PosX <= row0PosX) {
+                       return TOUCH_LEFT_ARROW;
+               }
+               else if(PosX >= (UGAWidth - row0PosX)) {
+                       return TOUCH_RIGHT_ARROW;
+               }
+       } else if(PosY >= row1PosY && PosY <= row1PosY + TileSizes[1]) {
+               itemRow = 1;
+       } else { // Y coordinate is outside of either row
+               return TOUCH_NO_ITEM;
+       }
+       
+       UINTN ItemIndex = TOUCH_NO_ITEM;
+       
+       itemPosX = AllocatePool(sizeof(UINTN) * Screen->EntryCount);
+       row0PosXRunning = row0PosX;
+       row1PosXRunning = row1PosX;
+       for (i = 0; i <= State->MaxIndex; i++) {
+               if (Screen->Entries[i]->Row == 0) {
+                       itemPosX[i] = row0PosXRunning;
+                       row0PosXRunning += TileSizes[0] + TILE_XSPACING;
+               } else {
+                       itemPosX[i] = row1PosXRunning;
+                       row1PosXRunning += TileSizes[1] + TILE_XSPACING;
+               }
+       }
+       
+       for (i = State->FirstVisible; i <= State->MaxIndex; i++) {
+      if (Screen->Entries[i]->Row == 0 && itemRow == 0) {
+         if (i <= State->LastVisible) {
+                        if(PosX >= itemPosX[i - State->FirstVisible] && PosX <= itemPosX[i - State->FirstVisible] + TileSizes[0]) {
+                               ItemIndex = i;
+                               break;
+                        }
+         } // if
+      } else if (Screen->Entries[i]->Row == 1 && itemRow == 1) {
+                 if(PosX >= itemPosX[i] && PosX <= itemPosX[i] + TileSizes[1]) {
+                       ItemIndex = i;
+                       break;
+                 }
+      }
+   }
+       
+       MyFreePool(itemPosX);
+       
+       return ItemIndex;
+} // VOID FindMainMenuItem()
+
 // Enable the user to edit boot loader options.
 // Returns TRUE if the user exited with edited options; FALSE if the user
 // pressed Esc to terminate the edit.
@@ -1244,6 +1383,14 @@ UINTN RunMainMenu(REFIT_MENU_SCREEN *Screen, CHAR16** DefaultSelection, REFIT_ME
     if (AllowGraphicsMode) {
         Style = GraphicsMenuStyle;
         MainStyle = MainMenuStyle;
+               
+               if(GlobalConfig.EnableTouch) {
+                       // Check for touch availability 
+                       EFI_STATUS status = refit_call3_wrapper(BS->LocateProtocol, &TouchGuid, NULL, (VOID **) &TouchProtocol);
+                       if(status == EFI_SUCCESS) {
+                               TouchEnabled = TouchActive = TRUE;
+                       }
+               }
     }
 
     while (!MenuExit) {
index 0b2db1fc56a9f7d6c345e0a1672cfb7eb8292c69..1c76fd1781a4e3551f5cfd12d9e93ed721035948 100644 (file)
@@ -90,6 +90,10 @@ typedef struct {
 #define SCROLL_MODE_TEXT  (0) /* Used in text mode & for GUI submenus */
 #define SCROLL_MODE_ICONS (1) /* Used for main GUI menu */
 
+#define TOUCH_NO_ITEM     (-1)
+#define TOUCH_LEFT_ARROW  (-2)
+#define TOUCH_RIGHT_ARROW (-3)
+
 struct _refit_menu_screen;
 
 VOID AddMenuInfoLine(IN REFIT_MENU_SCREEN *Screen, IN CHAR16 *InfoLine);
@@ -98,6 +102,7 @@ UINTN ComputeRow0PosY(VOID);
 VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINTN Function, IN CHAR16 *ParamText);
 UINTN RunMenu(IN REFIT_MENU_SCREEN *Screen, OUT REFIT_MENU_ENTRY **ChosenEntry);
 UINTN RunMainMenu(IN REFIT_MENU_SCREEN *Screen, IN CHAR16** DefaultSelection, OUT REFIT_MENU_ENTRY **ChosenEntry);
+UINTN FindMainMenuItem(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT64 PosX, IN UINT64 PosY);
 
 #endif