summaryrefslogtreecommitdiffstats
path: root/grub-core/osdep/windows/emuconsole.c
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/osdep/windows/emuconsole.c')
-rw-r--r--grub-core/osdep/windows/emuconsole.c308
1 files changed, 308 insertions, 0 deletions
diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c
new file mode 100644
index 0000000..4fb3693
--- /dev/null
+++ b/grub-core/osdep/windows/emuconsole.c
@@ -0,0 +1,308 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/err.h>
+
+#include <grub/emu/console.h>
+
+#include <windows.h>
+
+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)
+ {
+ unsigned kc = ir.Event.KeyEvent.wVirtualKeyCode;
+ if (kc < ARRAY_SIZE (windows_codes) && windows_codes[kc])
+ ret = windows_codes[kc];
+ 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);
+}