diff --git a/ChangeLog b/ChangeLog index 7f428252b..9852f06e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-10-14 Vladimir Serbinenko + + * grub-core/osdep/windows/emuconsole.c: New file. + 2013-10-14 Andrey Borzenkov * conf/Makefile.extra-dist: Add osdep/*/init.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 2d3ced74f..d9645f3cf 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -252,7 +252,9 @@ kernel = { emu = kern/emu/mm.c; emu = kern/emu/time.c; emu = kern/emu/cache.c; - emu = term/emu/console.c; + emu = osdep/emuconsole.c; + extra_dist = osdep/unix/emuconsole.c; + extra_dist = osdep/windows/emuconsole.c; emu = osdep/sleep.c; emu = osdep/init.c; diff --git a/grub-core/osdep/emuconsole.c b/grub-core/osdep/emuconsole.c new file mode 100644 index 000000000..13ede31d1 --- /dev/null +++ b/grub-core/osdep/emuconsole.c @@ -0,0 +1,5 @@ +#if defined (__MINGW32__) && !defined (__CYGWIN__) +#include "windows/emuconsole.c" +#else +#include "unix/emuconsole.c" +#endif diff --git a/grub-core/term/emu/console.c b/grub-core/osdep/unix/emuconsole.c similarity index 100% rename from grub-core/term/emu/console.c rename to grub-core/osdep/unix/emuconsole.c diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c new file mode 100644 index 000000000..7aca3b92f --- /dev/null +++ b/grub-core/osdep/windows/emuconsole.c @@ -0,0 +1,306 @@ +/* + * 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 + +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 + c->ncomb]; + 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; 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 grub_uint16_t +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 ((csbi.dwSize.X << 8) | csbi.dwSize.Y); +} + +static grub_uint16_t +grub_console_getxy (struct grub_term_output *term __attribute__ ((unused))) +{ + CONSOLE_SCREEN_BUFFER_INFO csbi; + + GetConsoleScreenBufferInfo (hStdout, &csbi); + + return ((csbi.dwCursorPosition.X << 8) | csbi.dwCursorPosition.Y); +} + +static void +grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)), + grub_uint8_t x, grub_uint8_t y) +{ + COORD coord = { x, 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, 0, 0); + tsz = csbi.dwSize.X * csbi.dwSize.Y; + + while (tsz--) + grub_console_putchar (term, &c); + + grub_console_gotoxy (term, 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 + }; + +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); +}