X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e366a10e438344bd1331f2de89d177079a91ba76..45f1cff5ce9364e781be5fc0819eeb2e2f6cf62e:/refind/line_edit.c diff --git a/refind/line_edit.c b/refind/line_edit.c new file mode 100644 index 0000000..8bb9fb4 --- /dev/null +++ b/refind/line_edit.c @@ -0,0 +1,217 @@ +// Line-editing functions borrowed from gummiboot (cursor_left(), +// cursor_right(), & line_edit()). + +/* + * Simple UEFI boot loader which executes configured EFI images, where the + * default entry is selected by a configured pattern (glob) or an on-screen + * menu. + * + * All gummiboot code is LGPL not GPL, to stay out of politics and to give + * the freedom of copying code from programs to possible future libraries. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * Copyright (C) 2012-2013 Kay Sievers + * Copyright (C) 2012 Harald Hoyer + * + * "Any intelligent fool can make things bigger, more complex, and more violent. +" + * -- Albert Einstein + */ + +#include "global.h" +#include "screen.h" +#include "lib.h" +#include "../include/refit_call_wrapper.h" + +static void cursor_left(UINTN *cursor, UINTN *first) +{ + if ((*cursor) > 0) + (*cursor)--; + else if ((*first) > 0) + (*first)--; +} + +static void cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) +{ + if ((*cursor)+2 < x_max) + (*cursor)++; + else if ((*first) + (*cursor) < len) + (*first)++; +} + +BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max) { + CHAR16 *line; + UINTN size; + UINTN len; + UINTN first; + UINTN y_pos = 3; + CHAR16 *print; + UINTN cursor; + BOOLEAN exit; + BOOLEAN enter; + + DrawScreenHeader(L"Line Editor"); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, (ConWidth - 71) / 2, ConHeight - 1); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, + L"Use cursor keys to edit, Esc to exit, Enter to boot with edited options"); + + if (!line_in) + line_in = L""; + size = StrLen(line_in) + 1024; + line = AllocatePool(size * sizeof(CHAR16)); + StrCpy(line, line_in); + len = StrLen(line); + print = AllocatePool(x_max * sizeof(CHAR16)); + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, TRUE); + + first = 0; + cursor = 0; + enter = FALSE; + exit = FALSE; + while (!exit) { + UINTN index; + EFI_STATUS err; + EFI_INPUT_KEY key; + UINTN i; + + i = len - first; + if (i >= x_max-2) + i = x_max-2; + CopyMem(print, line + first, i * sizeof(CHAR16)); + print[i++] = ' '; + print[i] = '\0'; + + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, 0, y_pos); + refit_call2_wrapper(ST->ConOut->OutputString, ST->ConOut, print); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + + refit_call3_wrapper(BS->WaitForEvent, 1, &ST->ConIn->WaitForKey, &index); + err = refit_call2_wrapper(ST->ConIn->ReadKeyStroke, ST->ConIn, &key); + if (EFI_ERROR(err)) + continue; + + switch (key.ScanCode) { + case SCAN_ESC: + exit = TRUE; + break; + case SCAN_HOME: + cursor = 0; + first = 0; + continue; + case SCAN_END: + cursor = len; + if (cursor >= x_max) { + cursor = x_max-2; + first = len - (x_max-2); + } + continue; + case SCAN_UP: + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] != ' ') + cursor_left(&cursor, &first); + while((first + cursor) && line[first + cursor] == ' ') + cursor_left(&cursor, &first); + if (first + cursor != len && first + cursor) + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DOWN: + while(line[first + cursor] && line[first + cursor] == ' ') + cursor_right(&cursor, &first, x_max, len); + while(line[first + cursor] && line[first + cursor] != ' ') + cursor_right(&cursor, &first, x_max, len); + while(line[first + cursor] && line[first + cursor] == ' ') + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_RIGHT: + if (first + cursor == len) + continue; + cursor_right(&cursor, &first, x_max, len); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_LEFT: + cursor_left(&cursor, &first); + refit_call3_wrapper(ST->ConOut->SetCursorPosition, ST->ConOut, cursor, y_pos); + continue; + case SCAN_DELETE: + if (len == 0) + continue; + if (first + cursor == len) + continue; + for (i = first + cursor; i < len; i++) + line[i] = line[i+1]; + line[len-1] = ' '; + len--; + continue; + } + + switch (key.UnicodeChar) { + case CHAR_LINEFEED: + case CHAR_CARRIAGE_RETURN: + *line_out = line; + line = NULL; + enter = TRUE; + exit = TRUE; + break; + case CHAR_BACKSPACE: + if (len == 0) + continue; + if (first == 0 && cursor == 0) + continue; + for (i = first + cursor-1; i < len; i++) + line[i] = line[i+1]; + len--; + if (cursor > 0) + cursor--; + if (cursor > 0 || first == 0) + continue; + /* show full line if it fits */ + if (len < x_max-2) { + cursor = first; + first = 0; + continue; + } + /* jump left to see what we delete */ + if (first > 10) { + first -= 10; + cursor = 10; + } else { + cursor = first; + first = 0; + } + continue; + case '\t': + case ' ' ... '~': + case 0x80 ... 0xffff: + if (len+1 == size) + continue; + for (i = len; i > first + cursor; i--) + line[i] = line[i-1]; + line[first + cursor] = key.UnicodeChar; + len++; + line[len] = '\0'; + if (cursor+2 < x_max) + cursor++; + else if (first + cursor < len) + first++; + continue; + } + } + + refit_call2_wrapper(ST->ConOut->EnableCursor, ST->ConOut, FALSE); + FreePool(print); + FreePool(line); + return enter; +} /* BOOLEAN line_edit() */