From a68629a93111126097aeb3b6fb3dc501ff472e6b Mon Sep 17 00:00:00 2001 From: longpanda Date: Thu, 7 Jan 2021 20:32:38 +0800 Subject: [PATCH] Add support for keyboard layout F5 ---> Keyboard Layouts --- .../grub-2.04/grub-core/Makefile.core.def | 5 + GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c | 133 +++++ .../MOD_SRC/grub-2.04/grub-core/term/setkey.c | 362 ++++++++++++++ GRUB2/MOD_SRC/grub-2.04/include/grub/term.h | 466 ++++++++++++++++++ GRUB2/MOD_SRC/grub-2.04/install.sh | 6 +- INSTALL/grub/debug.cfg | 106 ++-- INSTALL/grub/keyboard.cfg.gz | Bin 0 -> 2416 bytes 7 files changed, 1023 insertions(+), 55 deletions(-) create mode 100644 GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c create mode 100644 GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c create mode 100644 GRUB2/MOD_SRC/grub-2.04/include/grub/term.h create mode 100644 INSTALL/grub/keyboard.cfg.gz diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def b/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def index b9d87071..aeffad7b 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/Makefile.core.def @@ -1600,6 +1600,11 @@ module = { common = ventoy/miniz.c; }; +module = { + name = setkey; + common = term/setkey.c; +}; + module = { name = hello; common = hello/hello.c; diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c new file mode 100644 index 00000000..816a4058 --- /dev/null +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/term.c @@ -0,0 +1,133 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct grub_term_output *grub_term_outputs_disabled; +struct grub_term_input *grub_term_inputs_disabled; +struct grub_term_output *grub_term_outputs; +struct grub_term_input *grub_term_inputs; + +/* Current color state. */ +grub_uint8_t grub_term_normal_color = GRUB_TERM_DEFAULT_NORMAL_COLOR; +grub_uint8_t grub_term_highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR; + +void (*grub_term_poll_usb) (int wait_for_completion) = NULL; +void (*grub_net_poll_cards_idle) (void) = NULL; + +/* Put a Unicode character. */ +static void +grub_putcode_dumb (grub_uint32_t code, + struct grub_term_output *term) +{ + struct grub_unicode_glyph c = + { + .base = code, + .variant = 0, + .attributes = 0, + .ncomb = 0, + .estimated_width = 1 + }; + + if (code == '\t' && term->getxy) + { + int n; + + n = GRUB_TERM_TAB_WIDTH - ((term->getxy (term).x) + % GRUB_TERM_TAB_WIDTH); + while (n--) + grub_putcode_dumb (' ', term); + + return; + } + + (term->putchar) (term, &c); + if (code == '\n') + grub_putcode_dumb ('\r', term); +} + +static void +grub_xputs_dumb (const char *str) +{ + for (; *str; str++) + { + grub_term_output_t term; + grub_uint32_t code = *str; + if (code > 0x7f) + code = '?'; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_putcode_dumb (code, term); + } +} + +void (*grub_xputs) (const char *str) = grub_xputs_dumb; + +int (*grub_key_remap)(int key) = NULL; +int +grub_getkey_noblock (void) +{ + grub_term_input_t term; + + if (grub_term_poll_usb) + grub_term_poll_usb (0); + + if (grub_net_poll_cards_idle) + grub_net_poll_cards_idle (); + + FOR_ACTIVE_TERM_INPUTS(term) + { + int key = term->getkey (term); + if (grub_key_remap) + key = grub_key_remap(key); + if (key != GRUB_TERM_NO_KEY) + return key; + } + + return GRUB_TERM_NO_KEY; +} + +int +grub_getkey (void) +{ + int ret; + + grub_refresh (); + + while (1) + { + ret = grub_getkey_noblock (); + if (ret != GRUB_TERM_NO_KEY) + return ret; + grub_cpu_idle (); + } +} + +void +grub_refresh (void) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_refresh (term); +} diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c new file mode 100644 index 00000000..228df876 --- /dev/null +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/term/setkey.c @@ -0,0 +1,362 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define MAX_KEYMAP 255 + +struct keymap +{ + int cnt; + int in[MAX_KEYMAP]; + int out[MAX_KEYMAP]; +}; + +static struct keymap setkey_keymap; + +struct keysym +{ + const char *name; /* the name in unshifted state */ + int code; /* scan code */ +}; + +/* The table for key symbols. (from GRUB4DOS) */ +static struct keysym keysym_table[] = +{ + {"escape", GRUB_TERM_ESC}, // ESC + {"exclam", 0x21}, // '!' + {"at", 0x40}, // '@' + {"numbersign", 0x23}, // '#' + {"dollar", 0x24}, // '$' + {"percent", 0x25}, // '%' + {"caret", 0x5E}, // '^' + {"ampersand", 0x26}, // '&' + {"asterisk", 0x2A}, // '*' + {"parenleft", 0x28}, // '(' + {"parenright", 0x29}, // ')' + {"minus", 0x2D}, // '-' + {"underscore", 0x5F}, // '_' + {"equal", 0x3D}, // '=' + {"plus", 0x2B}, // '+' + {"backspace", GRUB_TERM_BACKSPACE}, // BS + {"ctrlbackspace", GRUB_TERM_CTRL | GRUB_TERM_BACKSPACE}, // (DEL) + {"tab", GRUB_TERM_TAB}, // Tab + {"bracketleft", 0x5B}, // '[' + {"braceleft", 0x7B}, // '{' + {"bracketright", 0x5D}, // ']' + {"braceright", 0x7D}, // '}' + {"enter", 0x0D}, // Enter + {"semicolon", 0x3B}, // ';' + {"colon", 0x3A}, // ':' + {"quote", 0x27}, // '\'' + {"doublequote", 0x22}, // '"' + {"backquote", 0x60}, // '`' + {"tilde", 0x7E}, // '~' + {"backslash", 0x5C}, // '\\' + {"bar", 0x7C}, // '|' + {"comma", 0x2C}, // ',' + {"less", 0x3C}, // '<' + {"period", 0x2E}, // '.' + {"greater", 0x3E}, // '>' + {"slash", 0x2F}, // '/' + {"question", 0x3F}, // '?' + {"space", 0x20}, // Space + {"F1", GRUB_TERM_KEY_F1}, + {"F2", GRUB_TERM_KEY_F2}, + {"F3", GRUB_TERM_KEY_F3}, + {"F4", GRUB_TERM_KEY_F4}, + {"F5", GRUB_TERM_KEY_F5}, + {"F6", GRUB_TERM_KEY_F6}, + {"F7", GRUB_TERM_KEY_F7}, + {"F8", GRUB_TERM_KEY_F8}, + {"F9", GRUB_TERM_KEY_F9}, + {"F10", GRUB_TERM_KEY_F10}, + {"F11", GRUB_TERM_KEY_F11}, + {"F12", GRUB_TERM_KEY_F12}, + {"home", GRUB_TERM_KEY_HOME}, + {"uparrow", GRUB_TERM_KEY_UP}, + {"pageup", GRUB_TERM_KEY_NPAGE}, // PgUp + {"leftarrow", GRUB_TERM_KEY_LEFT}, + {"center", GRUB_TERM_KEY_CENTER}, // keypad center key + {"rightarrow", GRUB_TERM_KEY_RIGHT}, + {"end", GRUB_TERM_KEY_END}, + {"downarrow", GRUB_TERM_KEY_DOWN}, + {"pagedown", GRUB_TERM_KEY_PPAGE}, // PgDn + {"insert", GRUB_TERM_KEY_INSERT}, // Insert + {"delete", GRUB_TERM_KEY_DC}, // Delete + {"shiftF1", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F1}, + {"shiftF2", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F2}, + {"shiftF3", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F3}, + {"shiftF4", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F4}, + {"shiftF5", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F5}, + {"shiftF6", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F6}, + {"shiftF7", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F7}, + {"shiftF8", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F8}, + {"shiftF9", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F9}, + {"shiftF10", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F10}, + {"shiftF11", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F11}, + {"shiftF12", GRUB_TERM_SHIFT | GRUB_TERM_KEY_F12}, + {"ctrlF1", GRUB_TERM_CTRL | GRUB_TERM_KEY_F1}, + {"ctrlF2", GRUB_TERM_CTRL | GRUB_TERM_KEY_F2}, + {"ctrlF3", GRUB_TERM_CTRL | GRUB_TERM_KEY_F3}, + {"ctrlF4", GRUB_TERM_CTRL | GRUB_TERM_KEY_F4}, + {"ctrlF5", GRUB_TERM_CTRL | GRUB_TERM_KEY_F5}, + {"ctrlF6", GRUB_TERM_CTRL | GRUB_TERM_KEY_F6}, + {"ctrlF7", GRUB_TERM_CTRL | GRUB_TERM_KEY_F7}, + {"ctrlF8", GRUB_TERM_CTRL | GRUB_TERM_KEY_F8}, + {"ctrlF9", GRUB_TERM_CTRL | GRUB_TERM_KEY_F9}, + {"ctrlF10", GRUB_TERM_CTRL | GRUB_TERM_KEY_F10}, + {"ctrlF11", GRUB_TERM_CTRL | GRUB_TERM_KEY_F11}, + {"ctrlF12", GRUB_TERM_CTRL | GRUB_TERM_KEY_F12}, + // A=Alt or AltGr. Provided by steve. + {"Aq", GRUB_TERM_ALT | 0x71}, + {"Aw", GRUB_TERM_ALT | 0x77}, + {"Ae", GRUB_TERM_ALT | 0x65}, + {"Ar", GRUB_TERM_ALT | 0x72}, + {"At", GRUB_TERM_ALT | 0x74}, + {"Ay", GRUB_TERM_ALT | 0x79}, + {"Au", GRUB_TERM_ALT | 0x75}, + {"Ai", GRUB_TERM_ALT | 0x69}, + {"Ao", GRUB_TERM_ALT | 0x6F}, + {"Ap", GRUB_TERM_ALT | 0x70}, + {"Aa", GRUB_TERM_ALT | 0x61}, + {"As", GRUB_TERM_ALT | 0x73}, + {"Ad", GRUB_TERM_ALT | 0x64}, + {"Af", GRUB_TERM_ALT | 0x66}, + {"Ag", GRUB_TERM_ALT | 0x67}, + {"Ah", GRUB_TERM_ALT | 0x68}, + {"Aj", GRUB_TERM_ALT | 0x6A}, + {"Ak", GRUB_TERM_ALT | 0x6B}, + {"Al", GRUB_TERM_ALT | 0x6C}, + {"Az", GRUB_TERM_ALT | 0x7A}, + {"Ax", GRUB_TERM_ALT | 0x78}, + {"Ac", GRUB_TERM_ALT | 0x63}, + {"Av", GRUB_TERM_ALT | 0x76}, + {"Ab", GRUB_TERM_ALT | 0x62}, + {"An", GRUB_TERM_ALT | 0x6E}, + {"Am", GRUB_TERM_ALT | 0x6D}, + {"A1", GRUB_TERM_ALT | 0x31}, + {"A2", GRUB_TERM_ALT | 0x32}, + {"A3", GRUB_TERM_ALT | 0x33}, + {"A4", GRUB_TERM_ALT | 0x34}, + {"A5", GRUB_TERM_ALT | 0x35}, + {"A6", GRUB_TERM_ALT | 0x36}, + {"A7", GRUB_TERM_ALT | 0x37}, + {"A8", GRUB_TERM_ALT | 0x38}, + {"A9", GRUB_TERM_ALT | 0x39}, + {"A0", GRUB_TERM_ALT | 0x30}, + //{"oem102", 0x5c}, + //{"shiftoem102", 0x7c}, + {"Aminus", GRUB_TERM_ALT | 0x2D}, + {"Aequal", GRUB_TERM_ALT | 0x3D}, + {"Abracketleft", GRUB_TERM_ALT | 0x5B}, + {"Abracketright", GRUB_TERM_ALT | 0x5D}, + {"Asemicolon", GRUB_TERM_ALT | 0x3B}, + {"Aquote", GRUB_TERM_ALT | 0x27}, + {"Abackquote", GRUB_TERM_ALT | 0x60}, + {"Abackslash", GRUB_TERM_ALT | 0x5C}, + {"Acomma", GRUB_TERM_ALT | 0x2C}, + {"Aperiod", GRUB_TERM_ALT | 0x2E}, + {"Aslash", GRUB_TERM_ALT | 0x2F}, + {"Acolon", GRUB_TERM_ALT | 0x3A}, + {"Aplus", GRUB_TERM_ALT | 0x2B}, + {"Aless", GRUB_TERM_ALT | 0x3C}, + {"Aunderscore", GRUB_TERM_ALT | 0x5F}, + {"Agreater", GRUB_TERM_ALT | 0x3E}, + {"Aquestion", GRUB_TERM_ALT | 0x3F}, + {"Atilde", GRUB_TERM_ALT | 0x7E}, + {"Abraceleft", GRUB_TERM_ALT | 0x7B}, + {"Abar", GRUB_TERM_ALT | 0x7C}, + {"Abraceright", GRUB_TERM_ALT | 0x7D}, + {"Adoublequote", GRUB_TERM_ALT | 0x22}, +}; + +static int grub_keymap_getkey (int key) +{ + int i; + if (key == GRUB_TERM_NO_KEY) + return key; + if (setkey_keymap.cnt > MAX_KEYMAP) + setkey_keymap.cnt = MAX_KEYMAP; + for (i = 0; i < setkey_keymap.cnt; i++) + { + if (key == setkey_keymap.in[i]) + { + key = setkey_keymap.out[i]; + break; + } + } + return key; +} + +static void +grub_keymap_reset (void) +{ + grub_memset (&setkey_keymap, 0, sizeof (struct keymap)); +} + +static grub_err_t +grub_keymap_add (int in, int out) +{ + if (in == GRUB_TERM_NO_KEY || out == GRUB_TERM_NO_KEY) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid key: %d -> %d", in, out); + if (setkey_keymap.cnt >= MAX_KEYMAP) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, + "keymap FULL %d", setkey_keymap.cnt); + setkey_keymap.in[setkey_keymap.cnt] = in; + setkey_keymap.out[setkey_keymap.cnt] = out; + setkey_keymap.cnt++; + return GRUB_ERR_NONE; +} + +static void +grub_keymap_enable (void) +{ + grub_key_remap = grub_keymap_getkey; +} + +static void +grub_keymap_disable (void) +{ + grub_key_remap = NULL; +} + +static void +grub_keymap_status (void) +{ + int i; + if (setkey_keymap.cnt > MAX_KEYMAP) + setkey_keymap.cnt = MAX_KEYMAP; + for (i = 0; i < setkey_keymap.cnt; i++) + { + grub_printf ("0x%x -> 0x%x\n", setkey_keymap.in[i], setkey_keymap.out[i]); + } +} + +static const struct grub_arg_option options[] = +{ + {"reset", 'r', 0, N_("Reset keymap."), 0, 0}, + {"enable", 'e', 0, N_("Enable keymap."), 0, 0}, + {"disable", 'd', 0, N_("Disable keymap."), 0, 0}, + {"status", 's', 0, N_("Display keymap."), 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +enum options +{ + SETKEY_RESET, + SETKEY_ENABLE, + SETKEY_DISABLE, + SETKEY_STATUS, +}; + +static int +ishex (const char *str) +{ + if (grub_strlen (str) < 3 || str[0] != '0') + return 0; + if (str[1] != 'x' && str[1] != 'X') + return 0; + return 1; +} + +static int +parse_key (const char *str) +{ + int i; + if (ishex (str)) + return grub_strtol (str, NULL, 16); + if (grub_strlen (str) == 1) + return (int) str[0]; + for (i = 0; i < (int) (sizeof (keysym_table) / sizeof (keysym_table[0])); i++) + { + if (grub_strcmp (str, keysym_table[i].name) == 0) + return keysym_table[i].code; + } + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid key %s", str); + return 0; +} + +static grub_err_t +grub_cmd_setkey (grub_extcmd_context_t ctxt, int argc, char **args) +{ + struct grub_arg_list *state = ctxt->state; + int in, out; + if (state[SETKEY_ENABLE].set) + { + grub_keymap_enable (); + goto out; + } + if (state[SETKEY_DISABLE].set) + { + grub_keymap_disable (); + goto out; + } + if (state[SETKEY_RESET].set) + { + grub_keymap_reset (); + goto out; + } + if (state[SETKEY_STATUS].set) + { + grub_keymap_status (); + goto out; + } + if (argc != 2) + { + grub_printf + ("Key names: 0-9, A-Z, a-z or escape, exclam, at, numbersign, dollar," + "percent, caret, ampersand, asterisk, parenleft, parenright, minus," + "underscore, equal, plus, backspace, tab, bracketleft, braceleft," + "bracketright, braceright, enter, semicolon, colon, quote, doublequote," + "backquote, tilde, backslash, bar, comma, less, period, greater," + "slash, question, alt, space, delete, [ctrl|shift]F1-12." + "For Alt+ prefix with A, e.g. \'setkey at Aequal\'."); + goto out; + } + in = parse_key (args[1]); + out = parse_key (args[0]); + if (!in || !out) + goto out; + grub_keymap_add (in, out); +out: + return grub_errno; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(setkey) +{ + cmd = grub_register_extcmd ("setkey", grub_cmd_setkey, 0, N_("NEW_KEY USA_KEY"), + N_("Map default USA_KEY to NEW_KEY."), options); +} + +GRUB_MOD_FINI(setkey) +{ + grub_unregister_extcmd (cmd); +} diff --git a/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h new file mode 100644 index 00000000..a2bd7a99 --- /dev/null +++ b/GRUB2/MOD_SRC/grub-2.04/include/grub/term.h @@ -0,0 +1,466 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2005,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_TERM_HEADER +#define GRUB_TERM_HEADER 1 + +#define GRUB_TERM_NO_KEY 0 + +/* Internal codes used by GRUB to represent terminal input. */ +/* Only for keys otherwise not having shifted modification. */ +#define GRUB_TERM_SHIFT 0x01000000 +#define GRUB_TERM_CTRL 0x02000000 +#define GRUB_TERM_ALT 0x04000000 + +/* Keys without associated character. */ +#define GRUB_TERM_EXTENDED 0x00800000 +#define GRUB_TERM_KEY_MASK 0x00ffffff + +#define GRUB_TERM_KEY_LEFT (GRUB_TERM_EXTENDED | 0x4b) +#define GRUB_TERM_KEY_RIGHT (GRUB_TERM_EXTENDED | 0x4d) +#define GRUB_TERM_KEY_UP (GRUB_TERM_EXTENDED | 0x48) +#define GRUB_TERM_KEY_DOWN (GRUB_TERM_EXTENDED | 0x50) +#define GRUB_TERM_KEY_HOME (GRUB_TERM_EXTENDED | 0x47) +#define GRUB_TERM_KEY_END (GRUB_TERM_EXTENDED | 0x4f) +#define GRUB_TERM_KEY_DC (GRUB_TERM_EXTENDED | 0x53) +#define GRUB_TERM_KEY_PPAGE (GRUB_TERM_EXTENDED | 0x49) +#define GRUB_TERM_KEY_NPAGE (GRUB_TERM_EXTENDED | 0x51) +#define GRUB_TERM_KEY_F1 (GRUB_TERM_EXTENDED | 0x3b) +#define GRUB_TERM_KEY_F2 (GRUB_TERM_EXTENDED | 0x3c) +#define GRUB_TERM_KEY_F3 (GRUB_TERM_EXTENDED | 0x3d) +#define GRUB_TERM_KEY_F4 (GRUB_TERM_EXTENDED | 0x3e) +#define GRUB_TERM_KEY_F5 (GRUB_TERM_EXTENDED | 0x3f) +#define GRUB_TERM_KEY_F6 (GRUB_TERM_EXTENDED | 0x40) +#define GRUB_TERM_KEY_F7 (GRUB_TERM_EXTENDED | 0x41) +#define GRUB_TERM_KEY_F8 (GRUB_TERM_EXTENDED | 0x42) +#define GRUB_TERM_KEY_F9 (GRUB_TERM_EXTENDED | 0x43) +#define GRUB_TERM_KEY_F10 (GRUB_TERM_EXTENDED | 0x44) +#define GRUB_TERM_KEY_F11 (GRUB_TERM_EXTENDED | 0x57) +#define GRUB_TERM_KEY_F12 (GRUB_TERM_EXTENDED | 0x58) +#define GRUB_TERM_KEY_INSERT (GRUB_TERM_EXTENDED | 0x52) +#define GRUB_TERM_KEY_CENTER (GRUB_TERM_EXTENDED | 0x4c) + +/* Hex value is used for ESC, since '\e' is nonstandard */ +#define GRUB_TERM_ESC 0x1b +#define GRUB_TERM_TAB '\t' +#define GRUB_TERM_BACKSPACE '\b' + +#define GRUB_PROGRESS_NO_UPDATE -1 +#define GRUB_PROGRESS_FAST 0 +#define GRUB_PROGRESS_SLOW 2 + +#ifndef ASM_FILE + +#include +#include +#include +#include +#include + +/* These are used to represent the various color states we use. */ +typedef enum + { + /* The color used to display all text that does not use the + user defined colors below. */ + GRUB_TERM_COLOR_STANDARD, + /* The user defined colors for normal text. */ + GRUB_TERM_COLOR_NORMAL, + /* The user defined colors for highlighted text. */ + GRUB_TERM_COLOR_HIGHLIGHT + } +grub_term_color_state; + +/* Flags for representing the capabilities of a terminal. */ +/* Some notes about the flags: + - These flags are used by higher-level functions but not terminals + themselves. + - If a terminal is dumb, you may assume that only putchar, getkey and + checkkey are called. + - Some fancy features (setcolorstate, setcolor and setcursor) can be set + to NULL. */ + +/* Set when input characters shouldn't be echoed back. */ +#define GRUB_TERM_NO_ECHO (1 << 0) +/* Set when the editing feature should be disabled. */ +#define GRUB_TERM_NO_EDIT (1 << 1) +/* Set when the terminal cannot do fancy things. */ +#define GRUB_TERM_DUMB (1 << 2) +/* Which encoding does terminal expect stream to be. */ +#define GRUB_TERM_CODE_TYPE_SHIFT 3 +#define GRUB_TERM_CODE_TYPE_MASK (7 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Only ASCII characters accepted. */ +#define GRUB_TERM_CODE_TYPE_ASCII (0 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Expects CP-437 characters (ASCII + pseudographics). */ +#define GRUB_TERM_CODE_TYPE_CP437 (1 << GRUB_TERM_CODE_TYPE_SHIFT) +/* UTF-8 stream in logical order. Usually used for terminals + which just forward the stream to another computer. */ +#define GRUB_TERM_CODE_TYPE_UTF8_LOGICAL (2 << GRUB_TERM_CODE_TYPE_SHIFT) +/* UTF-8 in visual order. Like UTF-8 logical but for buggy endpoints. */ +#define GRUB_TERM_CODE_TYPE_UTF8_VISUAL (3 << GRUB_TERM_CODE_TYPE_SHIFT) +/* Glyph description in visual order. */ +#define GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS (4 << GRUB_TERM_CODE_TYPE_SHIFT) + + +/* Bitmasks for modifier keys returned by grub_getkeystatus. */ +#define GRUB_TERM_STATUS_RSHIFT (1 << 0) +#define GRUB_TERM_STATUS_LSHIFT (1 << 1) +#define GRUB_TERM_STATUS_RCTRL (1 << 2) +#define GRUB_TERM_STATUS_RALT (1 << 3) +#define GRUB_TERM_STATUS_SCROLL (1 << 4) +#define GRUB_TERM_STATUS_NUM (1 << 5) +#define GRUB_TERM_STATUS_CAPS (1 << 6) +#define GRUB_TERM_STATUS_LCTRL (1 << 8) +#define GRUB_TERM_STATUS_LALT (1 << 9) + +/* Menu-related geometrical constants. */ + +/* The number of columns/lines between messages/borders/etc. */ +#define GRUB_TERM_MARGIN 1 + +/* The number of columns of scroll information. */ +#define GRUB_TERM_SCROLL_WIDTH 1 + +struct grub_term_input +{ + /* The next terminal. */ + struct grub_term_input *next; + struct grub_term_input **prev; + + /* The terminal name. */ + const char *name; + + /* Initialize the terminal. */ + grub_err_t (*init) (struct grub_term_input *term); + + /* Clean up the terminal. */ + grub_err_t (*fini) (struct grub_term_input *term); + + /* Get a character if any input character is available. Otherwise return -1 */ + int (*getkey) (struct grub_term_input *term); + + /* Get keyboard modifier status. */ + int (*getkeystatus) (struct grub_term_input *term); + + void *data; +}; +typedef struct grub_term_input *grub_term_input_t; + +/* Made in a way to fit into uint32_t and so be passed in a register. */ +struct grub_term_coordinate +{ + grub_uint16_t x; + grub_uint16_t y; +}; + +struct grub_term_output +{ + /* The next terminal. */ + struct grub_term_output *next; + struct grub_term_output **prev; + + /* The terminal name. */ + const char *name; + + /* Initialize the terminal. */ + grub_err_t (*init) (struct grub_term_output *term); + + /* Clean up the terminal. */ + grub_err_t (*fini) (struct grub_term_output *term); + + /* Put a character. C is encoded in Unicode. */ + void (*putchar) (struct grub_term_output *term, + const struct grub_unicode_glyph *c); + + /* Get the number of columns occupied by a given character C. C is + encoded in Unicode. */ + grub_size_t (*getcharwidth) (struct grub_term_output *term, + const struct grub_unicode_glyph *c); + + /* Get the screen size. */ + struct grub_term_coordinate (*getwh) (struct grub_term_output *term); + + /* Get the cursor position. The return value is ((X << 8) | Y). */ + struct grub_term_coordinate (*getxy) (struct grub_term_output *term); + + /* Go to the position (X, Y). */ + void (*gotoxy) (struct grub_term_output *term, + struct grub_term_coordinate pos); + + /* Clear the screen. */ + void (*cls) (struct grub_term_output *term); + + /* Set the current color to be used */ + void (*setcolorstate) (struct grub_term_output *term, + grub_term_color_state state); + + /* Turn on/off the cursor. */ + void (*setcursor) (struct grub_term_output *term, int on); + + /* Update the screen. */ + void (*refresh) (struct grub_term_output *term); + + /* gfxterm only: put in fullscreen mode. */ + grub_err_t (*fullscreen) (void); + + /* The feature flags defined above. */ + grub_uint32_t flags; + + /* Progress data. */ + grub_uint32_t progress_update_divisor; + grub_uint32_t progress_update_counter; + + void *data; +}; +typedef struct grub_term_output *grub_term_output_t; + +#define GRUB_TERM_DEFAULT_NORMAL_COLOR 0x07 +#define GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR 0x70 +#define GRUB_TERM_DEFAULT_STANDARD_COLOR 0x07 + +/* Current color state. */ +extern grub_uint8_t EXPORT_VAR(grub_term_normal_color); +extern grub_uint8_t EXPORT_VAR(grub_term_highlight_color); + +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs_disabled); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs_disabled); +extern struct grub_term_output *EXPORT_VAR(grub_term_outputs); +extern struct grub_term_input *EXPORT_VAR(grub_term_inputs); + +static inline void +grub_term_register_input (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + if (grub_term_inputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); + } +} + +static inline void +grub_term_register_input_inactive (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs_disabled), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_input_active (const char *name __attribute__ ((unused)), + grub_term_input_t term) +{ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_inputs), GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_output (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + if (grub_term_outputs) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); + else + { + /* If this is the first terminal, enable automatically. */ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); + } +} + +static inline void +grub_term_register_output_inactive (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs_disabled), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_register_output_active (const char *name __attribute__ ((unused)), + grub_term_output_t term) +{ + if (! term->init || term->init (term) == GRUB_ERR_NONE) + grub_list_push (GRUB_AS_LIST_P (&grub_term_outputs), + GRUB_AS_LIST (term)); +} + +static inline void +grub_term_unregister_input (grub_term_input_t term) +{ + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); +} + +static inline void +grub_term_unregister_output (grub_term_output_t term) +{ + grub_list_remove (GRUB_AS_LIST (term)); + grub_list_remove (GRUB_AS_LIST (term)); +} + +#define FOR_ACTIVE_TERM_INPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_inputs)) +#define FOR_DISABLED_TERM_INPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_inputs_disabled)) +#define FOR_ACTIVE_TERM_OUTPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_outputs)) +#define FOR_DISABLED_TERM_OUTPUTS(var) FOR_LIST_ELEMENTS((var), (grub_term_outputs_disabled)) + +void grub_putcode (grub_uint32_t code, struct grub_term_output *term); +int EXPORT_FUNC(grub_getkey) (void); +int EXPORT_FUNC(grub_getkey_noblock) (void); +extern int (*EXPORT_VAR (grub_key_remap))(int key); +void grub_cls (void); +void EXPORT_FUNC(grub_refresh) (void); +void grub_puts_terminal (const char *str, struct grub_term_output *term); +struct grub_term_coordinate *grub_term_save_pos (void); +void grub_term_restore_pos (struct grub_term_coordinate *pos); + +static inline unsigned grub_term_width (struct grub_term_output *term) +{ + return term->getwh(term).x ? : 80; +} + +static inline unsigned grub_term_height (struct grub_term_output *term) +{ + return term->getwh(term).y ? : 24; +} + +static inline struct grub_term_coordinate +grub_term_getxy (struct grub_term_output *term) +{ + return term->getxy (term); +} + +static inline void +grub_term_refresh (struct grub_term_output *term) +{ + if (term->refresh) + term->refresh (term); +} + +static inline void +grub_term_gotoxy (struct grub_term_output *term, struct grub_term_coordinate pos) +{ + term->gotoxy (term, pos); +} + +static inline void +grub_term_setcolorstate (struct grub_term_output *term, + grub_term_color_state state) +{ + if (term->setcolorstate) + term->setcolorstate (term, state); +} + +static inline void +grub_setcolorstate (grub_term_color_state state) +{ + struct grub_term_output *term; + + FOR_ACTIVE_TERM_OUTPUTS(term) + grub_term_setcolorstate (term, state); +} + +/* Turn on/off the cursor. */ +static inline void +grub_term_setcursor (struct grub_term_output *term, int on) +{ + if (term->setcursor) + term->setcursor (term, on); +} + +static inline void +grub_term_cls (struct grub_term_output *term) +{ + if (term->cls) + (term->cls) (term); + else + { + grub_putcode ('\n', term); + grub_term_refresh (term); + } +} + +#if HAVE_FONT_SOURCE + +grub_size_t +grub_unicode_estimate_width (const struct grub_unicode_glyph *c); + +#else + +static inline grub_size_t +grub_unicode_estimate_width (const struct grub_unicode_glyph *c __attribute__ ((unused))) +{ + if (grub_unicode_get_comb_type (c->base)) + return 0; + return 1; +} + +#endif + +#define GRUB_TERM_TAB_WIDTH 8 + +static inline grub_size_t +grub_term_getcharwidth (struct grub_term_output *term, + const struct grub_unicode_glyph *c) +{ + if (c->base == '\t') + return GRUB_TERM_TAB_WIDTH; + + if (term->getcharwidth) + return term->getcharwidth (term, c); + else if (((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_UTF8_LOGICAL) + || ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_UTF8_VISUAL) + || ((term->flags & GRUB_TERM_CODE_TYPE_MASK) + == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS)) + return grub_unicode_estimate_width (c); + else + return 1; +} + +struct grub_term_autoload +{ + struct grub_term_autoload *next; + char *name; + char *modname; +}; + +extern struct grub_term_autoload *grub_term_input_autoload; +extern struct grub_term_autoload *grub_term_output_autoload; + +static inline void +grub_print_spaces (struct grub_term_output *term, int number_spaces) +{ + while (--number_spaces >= 0) + grub_putcode (' ', term); +} + +extern void (*EXPORT_VAR (grub_term_poll_usb)) (int wait_for_completion); + +#define GRUB_TERM_REPEAT_PRE_INTERVAL 400 +#define GRUB_TERM_REPEAT_INTERVAL 50 + +#endif /* ! ASM_FILE */ + +#endif /* ! GRUB_TERM_HEADER */ diff --git a/GRUB2/MOD_SRC/grub-2.04/install.sh b/GRUB2/MOD_SRC/grub-2.04/install.sh index 2bfd1839..253d1cbd 100644 --- a/GRUB2/MOD_SRC/grub-2.04/install.sh +++ b/GRUB2/MOD_SRC/grub-2.04/install.sh @@ -12,12 +12,12 @@ make install PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/ net_modules_legacy="net tftp http" -all_modules_legacy="date drivemap blocklist regexp newc vga_text ntldr search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_gpt part_msdos fat exfat ntfs loopback gzio normal udf gfxmenu gfxterm gfxterm_background gfxterm_menu" +all_modules_legacy="setkey date drivemap blocklist regexp newc vga_text ntldr search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_gpt part_msdos fat exfat ntfs loopback gzio normal udf gfxmenu gfxterm gfxterm_background gfxterm_menu" net_modules_uefi="efinet net tftp http" -all_modules_uefi="blocklist ventoy test regexp newc search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu" +all_modules_uefi="setkey blocklist ventoy test regexp newc search at_keyboard usb_keyboard gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu" -all_modules_arm64_uefi="blocklist ventoy test regexp newc search gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop video video_fb gfxterm_background gfxterm_menu" +all_modules_arm64_uefi="setkey blocklist ventoy test regexp newc search gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop video video_fb gfxterm_background gfxterm_menu" if [ "$1" = "uefi" ]; then diff --git a/INSTALL/grub/debug.cfg b/INSTALL/grub/debug.cfg index b9b4065c..19e4733b 100644 --- a/INSTALL/grub/debug.cfg +++ b/INSTALL/grub/debug.cfg @@ -1,4 +1,58 @@ +source $prefix/keyboard.cfg.gz + +submenu "Resolution Configuration" --class=debug_resolution { + menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { + echo 'Return ...' + } + + vt_update_cur_video_mode VT_CUR_MODE + set vdid=0 + while [ $vdid -lt $VTOY_VIDEO_MODE_NUM ]; do + vt_get_video_mode $vdid vtCurMode + + unset vtActive + if [ "$vtCurMode" = "$VT_CUR_MODE" ]; then + set vtActive="[*]" + fi + + menuentry "$vtCurMode $vtActive" --class=debug_videomode VTOY_RUN_RET { + terminal_output console + set gfxmode=$1 + terminal_output gfxterm + } + + vt_incr vdid 1 + done +} + +submenu "Screen Display Mode" --class=debug_screen_mode { + menuentry 'Force Text Mode' --class=debug_text_mode { + terminal_output console + } + menuentry 'Force Graphics Mode' --class=debug_gui_mode { + terminal_output gfxterm + } + menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { + echo 'Return ...' + } +} + +if [ "$grub_platform" != "pc" ]; then + submenu 'Ventoy UEFI Utilities' --class=debug_util { + menuentry 'Fixup Windows BlinitializeLibrary Failure' --class=debug_util_blinit { + chainloader ${vtoy_path}/vtoyutil_${VTOY_EFI_ARCH}.efi env_param=${env_param} ${vtdebug_flag} feature=fix_windows_mmap + boot + echo -e "\npress ENTER to exit ..." + read vtInputKey + } + + menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { + echo 'Return ...' + } + } +fi + submenu 'Check plugin json configuration (ventoy.json)' --class=debug_json { menuentry 'Check global control plugin configuration' --class=debug_control { @@ -118,58 +172,6 @@ submenu 'Check plugin json configuration (ventoy.json)' --class=debug_json { } -submenu "Resolution Configuration" --class=debug_resolution { - menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { - echo 'Return ...' - } - - vt_update_cur_video_mode VT_CUR_MODE - set vdid=0 - while [ $vdid -lt $VTOY_VIDEO_MODE_NUM ]; do - vt_get_video_mode $vdid vtCurMode - - unset vtActive - if [ "$vtCurMode" = "$VT_CUR_MODE" ]; then - set vtActive="[*]" - fi - - menuentry "$vtCurMode $vtActive" --class=debug_videomode VTOY_RUN_RET { - terminal_output console - set gfxmode=$1 - terminal_output gfxterm - } - - vt_incr vdid 1 - done -} - -submenu "Screen Display Mode" --class=debug_screen_mode { - menuentry 'Force Text Mode' --class=debug_text_mode { - terminal_output console - } - menuentry 'Force Graphics Mode' --class=debug_gui_mode { - terminal_output gfxterm - } - menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { - echo 'Return ...' - } -} - -if [ "$grub_platform" != "pc" ]; then - submenu 'Ventoy UEFI Utilities' --class=debug_util { - menuentry 'Fixup Windows BlinitializeLibrary Failure' --class=debug_util_blinit { - chainloader ${vtoy_path}/vtoyutil_${VTOY_EFI_ARCH}.efi env_param=${env_param} ${vtdebug_flag} feature=fix_windows_mmap - boot - echo -e "\npress ENTER to exit ..." - read vtInputKey - } - - menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { - echo 'Return ...' - } - } -fi - menuentry 'Return to previous menu [Esc]' --class=vtoyret VTOY_RET { echo 'Return ...' } diff --git a/INSTALL/grub/keyboard.cfg.gz b/INSTALL/grub/keyboard.cfg.gz new file mode 100644 index 0000000000000000000000000000000000000000..aaa08262291deff4132f97e71d1863bcff757523 GIT binary patch literal 2416 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