On Mon, Aug 24, 2009 at 12:46:29AM +0200, Vladimir 'phcoder' Serbinenko wrote:

[Could you please preserve attributions in your replies? I've reinserted
one here so that it's clear who wrote what.]

> Colin Watson wrote:
> > The values I picked for the constants were convenient for i386-pc, but
> > that's because it's the only architecture that currently needs an
> > assembly implementation and it seemed to make sense to me to put the
> > harder work of transforming values around into C code.
> >
> > I'm not sure what you mean by "distinguish" here though. I included
> > constants for control and alt that are currently unused, which may
> > actually have been a mistake since the original Red Hat patch to GRUB 1
> > honoured those too in its hiddenmenu handling. Is that what you mean?
> 
> I mean that upper layer code knows whether it was left or right shift
> but it doesn't know whether it was left or right alt.

Oh, I see. There's no real need to distinguish here, so the attached
patch removes the distinction. Note that this should NOT be applied
as-is, as I have not updated the assembly implementation for this;
Robert is going to clean-room this in C (which should take all of a
minute or so :-) ), and I hope he can deal with the bit-banging at the
same time.

Thanks,

-- 
Colin Watson                                       [cjwat...@ubuntu.com]
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 =
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to