/* * GRUB -- GRand Unified Bootloader * Copyright (C) 2006,2007,2008,2013 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 static HANDLE hStdin, hStdout; static DWORD orig_mode; static int saved_orig; static void grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)), const struct grub_unicode_glyph *c) { TCHAR str[2 + 30]; unsigned i, j; DWORD written; /* For now, do not try to use a surrogate pair. */ if (c->base > 0xffff) str[0] = '?'; else str[0] = (c->base & 0xffff); j = 1; for (i = 0; i < c->ncomb && j+1 < ARRAY_SIZE (str); i++) if (c->base < 0xffff) str[j++] = grub_unicode_get_comb (c)[i].code; str[j] = 0; WriteConsole (hStdout, str, j, &written, NULL); } const unsigned windows_codes[] = { /* 0x21 */ [VK_PRIOR] = GRUB_TERM_KEY_PPAGE, /* 0x22 */ [VK_NEXT] = GRUB_TERM_KEY_NPAGE, /* 0x23 */ [VK_END] = GRUB_TERM_KEY_END, /* 0x24 */ [VK_HOME] = GRUB_TERM_KEY_HOME, /* 0x25 */ [VK_LEFT] = GRUB_TERM_KEY_LEFT, /* 0x26 */ [VK_UP] = GRUB_TERM_KEY_UP, /* 0x27 */ [VK_RIGHT] = GRUB_TERM_KEY_RIGHT, /* 0x28 */ [VK_DOWN] = GRUB_TERM_KEY_DOWN, /* 0x2e */ [VK_DELETE] = GRUB_TERM_KEY_DC, /* 0x70 */ [VK_F1] = GRUB_TERM_KEY_F1, /* 0x71 */ [VK_F2] = GRUB_TERM_KEY_F2, /* 0x72 */ [VK_F3] = GRUB_TERM_KEY_F3, /* 0x73 */ [VK_F4] = GRUB_TERM_KEY_F4, /* 0x74 */ [VK_F5] = GRUB_TERM_KEY_F5, /* 0x75 */ [VK_F6] = GRUB_TERM_KEY_F6, /* 0x76 */ [VK_F7] = GRUB_TERM_KEY_F7, /* 0x77 */ [VK_F8] = GRUB_TERM_KEY_F8, /* 0x78 */ [VK_F9] = GRUB_TERM_KEY_F9, /* 0x79 */ [VK_F10] = GRUB_TERM_KEY_F10, /* 0x7a */ [VK_F11] = GRUB_TERM_KEY_F11, /* 0x7b */ [VK_F12] = GRUB_TERM_KEY_F12, }; static int grub_console_getkey (struct grub_term_input *term __attribute__ ((unused))) { while (1) { DWORD nev; INPUT_RECORD ir; int ret; if (!GetNumberOfConsoleInputEvents (hStdin, &nev)) return GRUB_TERM_NO_KEY; if (nev == 0) return GRUB_TERM_NO_KEY; if (!ReadConsoleInput (hStdin, &ir, 1, &nev)) return GRUB_TERM_NO_KEY; if (ir.EventType != KEY_EVENT) continue; if (!ir.Event.KeyEvent.bKeyDown) continue; ret = ir.Event.KeyEvent.uChar.UnicodeChar; if (ret == 0) { if (ir.Event.KeyEvent.wVirtualKeyCode >= 0 && ir.Event.KeyEvent.wVirtualKeyCode < ARRAY_SIZE (windows_codes) && windows_codes[(int) ir.Event.KeyEvent.wVirtualKeyCode]) ret = windows_codes[(int) ir.Event.KeyEvent.wVirtualKeyCode]; else continue; if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) ret |= GRUB_TERM_SHIFT; } /* Workaround for AltGr bug. */ if (ir.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED) return ret; if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) ret |= GRUB_TERM_ALT; if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) ret |= GRUB_TERM_CTRL; return ret; } } static struct grub_term_coordinate grub_console_getwh (struct grub_term_output *term __attribute__ ((unused))) { CONSOLE_SCREEN_BUFFER_INFO csbi; csbi.dwSize.X = 80; csbi.dwSize.Y = 25; GetConsoleScreenBufferInfo (hStdout, &csbi); return (struct grub_term_coordinate) { csbi.dwSize.X, csbi.dwSize.Y }; } static struct grub_term_coordinate grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) { CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo (hStdout, &csbi); return (struct grub_term_coordinate) { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y }; } static void grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), struct grub_term_coordinate pos) { COORD coord = { pos.x, pos.y }; SetConsoleCursorPosition (hStdout, coord); } static void grub_console_cls (struct grub_term_output *term) { int tsz; CONSOLE_SCREEN_BUFFER_INFO csbi; struct grub_unicode_glyph c = { .base = ' ', .variant = 0, .attributes = 0, .ncomb = 0, .estimated_width = 1 }; GetConsoleScreenBufferInfo (hStdout, &csbi); SetConsoleTextAttribute (hStdout, 0); grub_console_gotoxy (term, (struct grub_term_coordinate) { 0, 0 }); tsz = csbi.dwSize.X * csbi.dwSize.Y; while (tsz--) grub_console_putchar (term, &c); grub_console_gotoxy (term, (struct grub_term_coordinate) { 0, 0 }); SetConsoleTextAttribute (hStdout, csbi.wAttributes); } static void grub_console_setcolorstate (struct grub_term_output *term __attribute__ ((unused)), grub_term_color_state state) { switch (state) { case GRUB_TERM_COLOR_STANDARD: SetConsoleTextAttribute (hStdout, GRUB_TERM_DEFAULT_STANDARD_COLOR & 0x7f); break; case GRUB_TERM_COLOR_NORMAL: SetConsoleTextAttribute (hStdout, grub_term_normal_color & 0x7f); break; case GRUB_TERM_COLOR_HIGHLIGHT: SetConsoleTextAttribute (hStdout, grub_term_highlight_color & 0x7f); break; default: break; } } static void grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), int on) { CONSOLE_CURSOR_INFO ci; ci.dwSize = 5; ci.bVisible = on; SetConsoleCursorInfo (hStdout, &ci); } static grub_err_t grub_efi_console_init (struct grub_term_output *term) { grub_console_setcursor (term, 1); return 0; } static grub_err_t grub_efi_console_fini (struct grub_term_output *term) { grub_console_setcursor (term, 1); return 0; } static grub_err_t grub_console_init_input (struct grub_term_input *term) { if (!saved_orig) { GetConsoleMode (hStdin, &orig_mode); } saved_orig = 1; SetConsoleMode (hStdin, orig_mode & ~ENABLE_ECHO_INPUT & ~ENABLE_LINE_INPUT & ~ENABLE_PROCESSED_INPUT); return GRUB_ERR_NONE; } static grub_err_t grub_console_fini_input (struct grub_term_input *term __attribute__ ((unused))) { SetConsoleMode (hStdin, orig_mode); saved_orig = 0; return GRUB_ERR_NONE; } static struct grub_term_input grub_console_term_input = { .name = "console", .getkey = grub_console_getkey, .init = grub_console_init_input, .fini = grub_console_fini_input, }; static struct grub_term_output grub_console_term_output = { .name = "console", .init = grub_efi_console_init, .fini = grub_efi_console_fini, .putchar = grub_console_putchar, .getwh = grub_console_getwh, .getxy = grub_console_getxy, .gotoxy = grub_console_gotoxy, .cls = grub_console_cls, .setcolorstate = grub_console_setcolorstate, .setcursor = grub_console_setcursor, .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS, .progress_update_divisor = GRUB_PROGRESS_FAST }; void grub_console_init (void) { hStdin = GetStdHandle (STD_INPUT_HANDLE); hStdout = GetStdHandle (STD_OUTPUT_HANDLE); grub_term_register_input ("console", &grub_console_term_input); grub_term_register_output ("console", &grub_console_term_output); } void grub_console_fini (void) { if (saved_orig) { SetConsoleMode (hStdin, orig_mode); saved_orig = 0; } grub_term_unregister_input (&grub_console_term_input); grub_term_unregister_output (&grub_console_term_output); }