diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/commands/sleep.c grub2-1.96+20090725.new/commands/sleep.c --- grub2-1.96+20090725/commands/sleep.c 2009-03-21 08:39:59.000000000 +0000 +++ grub2-1.96+20090725.new/commands/sleep.c 2009-08-24 10:17:58.000000000 +0100 @@ -43,6 +43,20 @@ grub_printf ("%d ", n); } +static int +grub_check_keyboard (void) +{ + int mods = grub_keystatus (); + if (mods >= 0 && (mods & GRUB_TERM_STATUS_SHIFT) != 0) + return 1; + + if (grub_checkkey () >= 0 && + GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) + return 1; + + return 0; +} + /* Based on grub_millisleep() from kern/generic/millisleep.c. */ static int grub_interruptible_millisleep (grub_uint32_t ms) @@ -52,8 +66,7 @@ start = grub_get_time_ms (); while (grub_get_time_ms () - start < ms) - if (grub_checkkey () >= 0 && - GRUB_TERM_ASCII_CHAR (grub_getkey ()) == GRUB_TERM_ESC) + if (grub_check_keyboard ()) return 1; return 0; @@ -74,7 +87,7 @@ if (n == 0) { /* Either `0' or broken input. */ - return 0; + return grub_check_keyboard (); } xy = grub_getxy (); diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/include/grub/i386/pc/console.h grub2-1.96+20090725.new/include/grub/i386/pc/console.h --- grub2-1.96+20090725/include/grub/i386/pc/console.h 2008-11-12 17:43:39.000000000 +0000 +++ grub2-1.96+20090725.new/include/grub/i386/pc/console.h 2009-08-24 10:17:58.000000000 +0100 @@ -42,6 +42,7 @@ /* These are global to share code between C and asm. */ int grub_console_checkkey (void); int grub_console_getkey (void); +int grub_console_keystatus (void); grub_uint16_t grub_console_getxy (void); void grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y); void grub_console_cls (void); diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/include/grub/term.h grub2-1.96+20090725.new/include/grub/term.h --- grub2-1.96+20090725/include/grub/term.h 2009-06-10 22:04:23.000000000 +0100 +++ grub2-1.96+20090725.new/include/grub/term.h 2009-08-24 10:17:58.000000000 +0100 @@ -72,6 +72,12 @@ #define GRUB_TERM_NEED_INIT (1 << 16) +/* Bitmasks for modifier keys returned by grub_keystatus. */ +#define GRUB_TERM_STATUS_SHIFT (1 << 0) +#define GRUB_TERM_STATUS_CTRL (1 << 1) +#define GRUB_TERM_STATUS_ALT (1 << 2) + + /* Unicode characters for fancy graphics. */ #define GRUB_TERM_DISP_LEFT 0x2190 #define GRUB_TERM_DISP_UP 0x2191 @@ -157,6 +163,9 @@ /* Get a character. */ int (*getkey) (void); + + /* Get keyboard modifier status. */ + int (*keystatus) (void); }; typedef struct grub_term_input *grub_term_input_t; @@ -275,6 +284,7 @@ grub_ssize_t EXPORT_FUNC(grub_getcharwidth) (grub_uint32_t code); int EXPORT_FUNC(grub_getkey) (void); int EXPORT_FUNC(grub_checkkey) (void); +int EXPORT_FUNC(grub_keystatus) (void); grub_uint16_t EXPORT_FUNC(grub_getwh) (void); grub_uint16_t EXPORT_FUNC(grub_getxy) (void); void EXPORT_FUNC(grub_gotoxy) (grub_uint8_t x, grub_uint8_t y); diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/kern/i386/pc/startup.S grub2-1.96+20090725.new/kern/i386/pc/startup.S --- grub2-1.96+20090725/kern/i386/pc/startup.S 2009-08-24 10:17:56.000000000 +0100 +++ grub2-1.96+20090725.new/kern/i386/pc/startup.S 2009-08-24 10:17:58.000000000 +0100 @@ -1285,6 +1285,25 @@ /* + * int grub_console_keystatus (void) + * Return keyboard modifier status in %al: + * bit 3: alt key down + * bit 2: ctrl key down + * bit 1: left shift key down + * bit 0: right shift key down + */ +FUNCTION(grub_console_keystatus) + /* keyboard status bits in BIOS Data Area */ + movw $0x0417, %bx + movb (%bx), %al + + /* Mask out everything but Shift, Ctrl, and Alt. */ + andl $0x000f, %eax + + ret + + +/* * grub_uint16_t grub_console_getxy (void) * BIOS call "INT 10H Function 03h" to get cursor position * Call with %ah = 0x03 diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/kern/term.c grub2-1.96+20090725.new/kern/term.c --- grub2-1.96+20090725/kern/term.c 2009-06-10 22:04:23.000000000 +0100 +++ grub2-1.96+20090725.new/kern/term.c 2009-08-24 10:17:58.000000000 +0100 @@ -140,6 +140,15 @@ return (grub_cur_term_input->checkkey) (); } +int +grub_keystatus (void) +{ + if (grub_cur_term_input->keystatus) + return (grub_cur_term_input->keystatus) (); + else + return 0; +} + grub_uint16_t grub_getxy (void) { diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/efi/console.c grub2-1.96+20090725.new/term/efi/console.c --- grub2-1.96+20090725/term/efi/console.c 2009-06-10 22:04:23.000000000 +0100 +++ grub2-1.96+20090725.new/term/efi/console.c 2009-08-24 10:17:58.000000000 +0100 @@ -337,6 +337,8 @@ .name = "console", .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, + /* EFI does not support reading modifier key status. */ + .keystatus = NULL, }; static struct grub_term_output grub_console_term_output = diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/i386/pc/at_keyboard.c grub2-1.96+20090725.new/term/i386/pc/at_keyboard.c --- grub2-1.96+20090725/term/i386/pc/at_keyboard.c 2009-04-14 19:12:14.000000000 +0100 +++ grub2-1.96+20090725.new/term/i386/pc/at_keyboard.c 2009-08-24 10:17:58.000000000 +0100 @@ -222,6 +222,9 @@ .fini = grub_keyboard_controller_fini, .checkkey = grub_at_keyboard_checkkey, .getkey = grub_at_keyboard_getkey, + /* Getting key modifier status is not possible without BIOS help; all we + * can do is spot when keys are pressed. */ + .keystatus = NULL, }; GRUB_MOD_INIT(at_keyboard) diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/i386/pc/console.c grub2-1.96+20090725.new/term/i386/pc/console.c --- grub2-1.96+20090725/term/i386/pc/console.c 2009-04-14 19:12:14.000000000 +0100 +++ grub2-1.96+20090725.new/term/i386/pc/console.c 2009-08-24 10:17:58.000000000 +0100 @@ -25,6 +25,7 @@ .name = "console", .checkkey = grub_console_checkkey, .getkey = grub_console_getkey, + .keystatus = grub_console_keystatus, }; static struct grub_term_output grub_console_term_output = diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/i386/pc/serial.c grub2-1.96+20090725.new/term/i386/pc/serial.c --- grub2-1.96+20090725/term/i386/pc/serial.c 2009-06-11 17:17:45.000000000 +0100 +++ grub2-1.96+20090725.new/term/i386/pc/serial.c 2009-08-24 10:17:58.000000000 +0100 @@ -465,6 +465,8 @@ .name = "serial", .checkkey = grub_serial_checkkey, .getkey = grub_serial_getkey, + /* We can't get key modifier status on serial consoles. */ + .keystatus = NULL, }; static struct grub_term_output grub_serial_term_output = diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/ieee1275/ofconsole.c grub2-1.96+20090725.new/term/ieee1275/ofconsole.c --- grub2-1.96+20090725/term/ieee1275/ofconsole.c 2009-06-10 22:04:23.000000000 +0100 +++ grub2-1.96+20090725.new/term/ieee1275/ofconsole.c 2009-08-24 10:17:58.000000000 +0100 @@ -396,6 +396,8 @@ .fini = grub_ofconsole_fini, .checkkey = grub_ofconsole_checkkey, .getkey = grub_ofconsole_getkey, + /* No attempt to support this for Open Firmware yet. */ + .keystatus = NULL, }; static struct grub_term_output grub_ofconsole_term_output = diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/term/usb_keyboard.c grub2-1.96+20090725.new/term/usb_keyboard.c --- grub2-1.96+20090725/term/usb_keyboard.c 2009-06-10 22:04:23.000000000 +0100 +++ grub2-1.96+20090725.new/term/usb_keyboard.c 2009-08-24 10:18:08.000000000 +0100 @@ -234,11 +234,51 @@ return key; } +static int +grub_usb_keyboard_keystatus (void) +{ + unsigned char data[8]; + int mods = 0; + int i; + grub_err_t err; + + for (i = 0; i < 50; i++) + { + /* Get_Report. */ + err = grub_usb_keyboard_getreport (usbdev, data); + + if (! err) + break; + } + + if (err) + return -1; + + grub_dprintf ("usb_keyboard", + "report: 0x%02x 0x%02x 0x%02x 0x%02x" + " 0x%02x 0x%02x 0x%02x 0x%02x\n", + data[0], data[1], data[2], data[3], + data[4], data[5], data[6], data[7]); + + /* Check Shift, Control, and Alt status. */ + if (data[0] & 0x02 || data[0] & 0x20) + mods |= GRUB_TERM_STATUS_SHIFT; + if (data[0] & 0x01 || data[0] & 0x10) + mods |= GRUB_TERM_STATUS_CTRL; + if (data[0] & 0x04 || data[0] & 0x40) + mods |= GRUB_TERM_STATUS_ALT; + + grub_errno = GRUB_ERR_NONE; + + return mods; +} + static struct grub_term_input grub_usb_keyboard_term = { .name = "usb_keyboard", .checkkey = grub_usb_keyboard_checkkey, .getkey = grub_usb_keyboard_getkey, + .keystatus = grub_usb_keyboard_keystatus, .next = 0 }; diff -Nur -x '*.orig' -x '*~' grub2-1.96+20090725/util/console.c grub2-1.96+20090725.new/util/console.c --- grub2-1.96+20090725/util/console.c 2009-07-07 21:03:03.000000000 +0100 +++ grub2-1.96+20090725.new/util/console.c 2009-08-24 10:17:58.000000000 +0100 @@ -350,6 +350,8 @@ .name = "console", .checkkey = grub_ncurses_checkkey, .getkey = grub_ncurses_getkey, + /* ncurses can't tell us keyboard modifier status. */ + .keystatus = NULL, }; static struct grub_term_output grub_ncurses_term_output =