All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Detect key modifier status in 'sleep --interruptible'
@ 2009-08-12 15:35 Colin Watson
  2009-08-12 16:10 ` Vladimir 'phcoder' Serbinenko
                   ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Colin Watson @ 2009-08-12 15:35 UTC (permalink / raw)
  To: grub-devel; +Cc: Kristian Høgsberg

[-- Attachment #1: Type: text/plain, Size: 1059 bytes --]

The attached patch arranges to make use of key modifier status in 'sleep
--interruptible', so that you can interrupt the sleep by pressing Shift.
The benefit of this is that on some architectures it makes it possible
and even sometimes reasonable to use an extremely short sleep for a
hiddenmenu-type arrangement - even a zero sleep - because on some
architectures you can query key modifier state asynchronously without
having to wait for make scancodes by way of key repeat or whatever, so
all the user needs to do is hold Shift as they come out of the BIOS.
While a zero sleep probably isn't a reasonable default for GRUB in
general, it's very useful if you're building single-boot out-of-the-box
systems where you just want to get on with booting the one installed OS.

This is based on previous work in GRUB Legacy by Kristian and Peter
(CCed). Peter tells me that Red Hat has an assignment already on file,
and it looks like mine is finally making some progress ...

Thanks,

-- 
Colin Watson                                       [cjwatson@ubuntu.com]

[-- Attachment #2: keystatus.diff --]
[-- Type: text/x-diff, Size: 10318 bytes --]

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-12 16:34:00.000000000 +0100
@@ -43,6 +43,22 @@
   grub_printf ("%d    ", n);
 }
 
+static int
+grub_check_keyboard (void)
+{
+  int mods = grub_keystatus ();
+  if (mods >= 0 &&
+      (mods & (GRUB_TERM_STATUS_LEFT_SHIFT |
+	       GRUB_TERM_STATUS_RIGHT_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 +68,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 +89,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-12 16:32:21.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-12 16:32:21.000000000 +0100
@@ -72,6 +72,13 @@
 #define GRUB_TERM_NEED_INIT	(1 << 16)
 
 
+/* Bitmasks for modifier keys returned by grub_keystatus.  */
+#define GRUB_TERM_STATUS_ALT		(1 << 3)
+#define GRUB_TERM_STATUS_CTRL		(1 << 2)
+#define GRUB_TERM_STATUS_LEFT_SHIFT	(1 << 1)
+#define GRUB_TERM_STATUS_RIGHT_SHIFT	(1 << 0)
+
+
 /* Unicode characters for fancy graphics.  */
 #define GRUB_TERM_DISP_LEFT	0x2190
 #define GRUB_TERM_DISP_UP	0x2191
@@ -157,6 +164,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 +285,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-12 16:32:18.000000000 +0100
+++ grub2-1.96+20090725.new/kern/i386/pc/startup.S	2009-08-12 16:32:21.000000000 +0100
@@ -1285,6 +1285,38 @@
 
 
 /*
+ * int grub_console_keystatus (void)
+ * BIOS call "INT 16H Function 12H" to get keyboard modifier status
+ *	Call with	%ah = 0x12
+ *	Return:		%al = keyboard state:
+ *				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)
+	pushl	%ebp
+
+	call	prot_to_real	/* enter real mode */
+	.code16
+
+	movb	$0x12, %ah
+	int	$0x16
+	movw	%ax, %dx
+
+	DATA32	call	real_to_prot
+	.code32
+
+	movw	%dx, %ax
+
+	/* Mask out numlock, capslock and insert state. */
+	andl	$0x0f0f, %eax
+
+	popl	%ebp
+	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-12 16:32:21.000000000 +0100
@@ -140,6 +140,12 @@
   return (grub_cur_term_input->checkkey) ();
 }
 
+int
+grub_keystatus (void)
+{
+  return (grub_cur_term_input->keystatus) ();
+}
+
 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-12 16:32:21.000000000 +0100
@@ -206,6 +206,13 @@
 }
 
 static int
+grub_console_keystatus (void)
+{
+  /* EFI does not support reading modifier key status.  */
+  return 0;
+}
+
+static int
 grub_console_getkey (void)
 {
   grub_efi_simple_input_interface_t *i;
@@ -337,6 +344,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/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-12 16:32:21.000000000 +0100
@@ -200,6 +200,14 @@
   return key;
 }
 
+static int
+grub_at_keyboard_keystatus (void)
+{
+  /* FIXME: I don't know if getting key modifier status is possible without
+   * BIOS help.  */
+  return 0;
+}
+
 static grub_err_t
 grub_keyboard_controller_init (void)
 {
@@ -222,6 +230,7 @@
     .fini = grub_keyboard_controller_fini,
     .checkkey = grub_at_keyboard_checkkey,
     .getkey = grub_at_keyboard_getkey,
+    .keystatus = grub_at_keyboard_keystatus,
   };
 
 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-12 16:32:21.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-12 16:32:21.000000000 +0100
@@ -259,6 +259,13 @@
   return c;
 }
 
+static int
+grub_serial_keystatus (void)
+{
+  /* We can't get key modifier status on serial consoles.  */
+  return 0;
+}
+
 /* Initialize a serial device. PORT is the port number for a serial device.
    SPEED is a DTE-DTE speed which must be one of these: 2400, 4800, 9600,
    19200, 38400, 57600 and 115200. WORD_LEN is the word length to be used
@@ -465,6 +472,7 @@
   .name = "serial",
   .checkkey = grub_serial_checkkey,
   .getkey = grub_serial_getkey,
+  .keystatus = grub_serial_keystatus,
 };
 
 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-12 16:32:21.000000000 +0100
@@ -227,6 +227,13 @@
   return key;
 }
 
+static int
+grub_ofconsole_keystatus (void)
+{
+  /* No attempt to support this for Open Firmware yet. */
+  return 0;
+}
+
 static grub_uint16_t
 grub_ofconsole_getxy (void)
 {
@@ -396,6 +403,7 @@
     .fini = grub_ofconsole_fini,
     .checkkey = grub_ofconsole_checkkey,
     .getkey = grub_ofconsole_getkey,
+    .keystatus = grub_ofconsole_keystatus,
   };
 
 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-12 16:32:21.000000000 +0100
@@ -234,6 +234,47 @@
   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)
+    mods |= GRUB_TERM_STATUS_LEFT_SHIFT;
+  if (data[0] & 0x20)
+    mods |= GRUB_TERM_STATUS_RIGHT_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",
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-12 16:32:21.000000000 +0100
@@ -258,6 +258,13 @@
   return c;
 }
 
+static int
+grub_ncurses_keystatus (void)
+{
+  /* ncurses can't tell us keyboard modifier status.  */
+  return 0;
+}
+
 static grub_uint16_t
 grub_ncurses_getxy (void)
 {
@@ -350,6 +357,7 @@
     .name = "console",
     .checkkey = grub_ncurses_checkkey,
     .getkey = grub_ncurses_getkey,
+    .keystatus = grub_ncurses_keystatus,
   };
 
 static struct grub_term_output grub_ncurses_term_output =

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2009-08-28 13:21 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-12 15:35 [PATCH] Detect key modifier status in 'sleep --interruptible' Colin Watson
2009-08-12 16:10 ` Vladimir 'phcoder' Serbinenko
2009-08-12 16:15   ` Vladimir 'phcoder' Serbinenko
2009-08-12 22:14   ` Colin Watson
2009-08-13 20:52     ` Robert Millan
2009-08-13 21:15       ` Colin Watson
2009-08-23 22:46     ` Vladimir 'phcoder' Serbinenko
2009-08-23 22:56       ` Robert Millan
2009-08-23 23:00         ` Vladimir 'phcoder' Serbinenko
2009-08-23 23:03           ` Robert Millan
2009-08-23 23:05             ` Vladimir 'phcoder' Serbinenko
2009-08-25 19:26         ` Robert Millan
2009-08-24  9:24       ` Colin Watson
2009-08-24 12:23         ` Robert Millan
2009-08-24 12:44           ` Robert Millan
2009-08-24 13:27           ` Colin Watson
2009-08-24 14:28             ` Robert Millan
2009-08-24 16:23               ` Colin Watson
2009-08-24 16:56                 ` Colin Watson
2009-08-24 17:03               ` Colin Watson
2009-08-24 22:04           ` Colin Watson
2009-08-24 22:41             ` Robert Millan
2009-08-24 23:02               ` Colin Watson
2009-08-26 15:33                 ` Colin Watson
2009-08-26 18:39                   ` Robert Millan
2009-08-26 20:26                     ` Colin Watson
2009-08-28 12:44                       ` Robert Millan
2009-08-28 13:20                         ` Colin Watson
2009-08-24 12:56         ` Robert Millan
2009-08-13 20:46 ` Robert Millan
2009-08-23 22:27 ` Robert Millan
2009-08-23 22:41   ` Vladimir 'phcoder' Serbinenko
2009-08-23 22:57     ` Robert Millan
2009-08-24  9:11   ` Colin Watson
2009-08-24 11:57     ` Robert Millan
2009-08-24 12:50       ` Vladimir 'phcoder' Serbinenko
2009-08-24 12:58       ` Michal Suchanek
2009-08-24 14:29         ` Robert Millan
2009-08-24 12:59       ` Colin Watson
2009-08-24 13:27       ` Robert Millan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.