grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Detect key modifier status in 'sleep --interruptible'


From: Colin Watson
Subject: Re: [PATCH] Detect key modifier status in 'sleep --interruptible'
Date: Mon, 24 Aug 2009 23:04:19 +0100
User-agent: Mutt/1.5.18 (2008-05-17)

On Mon, Aug 24, 2009 at 02:23:52PM +0200, Robert Millan wrote:
> I don't have time to test it, but what we want is roughly something like
> this.  If you would please test and confirm it's working the way you expected,
> it can be committed.

OK, here's a cleanup that (a) fixes some compilation errors in your
patch and (b) adds USB keyboard support back in. How does this look?

2009-08-24  Colin Watson  <address@hidden>
2009-08-24  Robert Millan  <address@hidden>

        Add `getkeystatus' terminal method.  Use it in `sleep' to detect
        Shift being held down.

        * include/grub/term.h (GRUB_TERM_STATUS_SHIFT,
        GRUB_TERM_STATUS_CTRL, GRUB_TERM_STATUS_ALT): Definitions for
        modifier key bitmasks.
        (struct grub_term_input): Add `getkeystatus' member.
        (grub_getkeystatus): Add prototype.
        * kern/term.c (grub_getkeystatus): New function.

        * include/grub/i386/pc/memory.h
        (GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR): New macro.
        (struct grub_machine_bios_data_area): Define necessary parts of BIOS
        Data Area layout.
        * term/i386/pc/console.c (grub_console_getkeystatus): New function.
        (grub_console_term_input): Set `getkeystatus' member.
        * term/usb_keyboard.c (grub_usb_keyboard_getkeystatus): New
        function.
        (grub_usb_keyboard_term): Set `getkeystatus' member.

        * commands/sleep.c (grub_check_keyboard): New function.
        (grub_interruptible_millisleep, grub_cmd_sleep): Use
        grub_check_keyboard, checking whether Shift is pressed in addition
        to checking for Escape.

Index: kern/term.c
===================================================================
--- kern/term.c (revision 2525)
+++ kern/term.c (working copy)
@@ -140,6 +140,15 @@
   return (grub_cur_term_input->checkkey) ();
 }
 
+int
+grub_getkeystatus (void)
+{
+  if (grub_cur_term_input->getkeystatus)
+    return (grub_cur_term_input->getkeystatus) ();
+  else
+    return 0;
+}
+
 grub_uint16_t
 grub_getxy (void)
 {
Index: include/grub/term.h
===================================================================
--- include/grub/term.h (revision 2525)
+++ include/grub/term.h (working copy)
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2005,2007,2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2005,2007,2008,2009  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
@@ -72,6 +72,12 @@
 #define GRUB_TERM_NEED_INIT    (1 << 16)
 
 
+/* Bitmasks for modifier keys returned by grub_getkeystatus.  */
+#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 (*getkeystatus) (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_getkeystatus) (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);
Index: include/grub/i386/pc/memory.h
===================================================================
--- include/grub/i386/pc/memory.h       (revision 2525)
+++ include/grub/i386/pc/memory.h       (working copy)
@@ -78,8 +78,20 @@
 /* The data segment of the pseudo real mode.  */
 #define GRUB_MEMORY_MACHINE_PSEUDO_REAL_DSEG   0x20
 
+#define GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR        0x400
+
 #ifndef ASM_FILE
 
+/* See http://heim.ifi.uio.no/~stanisls/helppc/bios_data_area.html for a
+   description of the BIOS Data Area layout.  */
+struct grub_machine_bios_data_area
+{
+  grub_uint8_t unused1[0x17];
+  grub_uint8_t keyboard_flag_lower; /* 0x17 */ 
+  grub_uint8_t keyboard_flag_upper; /* 0x17 */ 
+  grub_uint8_t unused2[0xf0 - 0x19];
+};
+
 struct grub_machine_mmap_entry
 {
   grub_uint32_t size;
Index: commands/sleep.c
===================================================================
--- commands/sleep.c    (revision 2525)
+++ commands/sleep.c    (working copy)
@@ -1,7 +1,7 @@
 /* sleep.c - Command to wait a specified number of seconds.  */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2006,2007,2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2006,2007,2008,2009  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
@@ -43,6 +43,20 @@
   grub_printf ("%d    ", n);
 }
 
+static int
+grub_check_keyboard (void)
+{
+  int mods = grub_getkeystatus ();
+  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 ();
Index: term/i386/pc/console.c
===================================================================
--- term/i386/pc/console.c      (revision 2525)
+++ term/i386/pc/console.c      (working copy)
@@ -1,6 +1,6 @@
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2002,2003,2005,2007,2008  Free Software Foundation, Inc.
+ *  Copyright (C) 2002,2003,2005,2007,2008,2009  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
@@ -16,15 +16,35 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <grub/machine/memory.h>
 #include <grub/machine/console.h>
 #include <grub/term.h>
 #include <grub/types.h>
 
+static const struct grub_machine_bios_data_area *bios_data_area = 
GRUB_MEMORY_MACHINE_BIOS_DATA_AREA_ADDR;
+
+static int
+grub_console_getkeystatus (void)
+{
+  grub_uint8_t status = bios_data_area->keyboard_flag_lower;
+  int mods = 0;
+
+  if (status & 0x03)
+    mods |= GRUB_TERM_STATUS_SHIFT;
+  if (status & 0x04)
+    mods |= GRUB_TERM_STATUS_CTRL;
+  if (status & 0x08)
+    mods |= GRUB_TERM_STATUS_ALT;
+
+  return mods;
+}
+
 static struct grub_term_input grub_console_term_input =
   {
     .name = "console",
     .checkkey = grub_console_checkkey,
     .getkey = grub_console_getkey,
+    .getkeystatus = grub_console_getkeystatus,
   };
 
 static struct grub_term_output grub_console_term_output =
Index: term/usb_keyboard.c
===================================================================
--- term/usb_keyboard.c (revision 2526)
+++ term/usb_keyboard.c (working copy)
@@ -238,11 +238,55 @@
   return key;
 }
 
+static int
+grub_usb_keyboard_getkeystatus (void)
+{
+  grub_uint8_t data[8];
+  int mods = 0;
+  grub_err_t err;
+  grub_uint64_t currtime;
+  int timeout = 50;
+
+  currtime = grub_get_time_ms ();
+  do
+    {
+      /* Get_Report.  */
+      err = grub_usb_keyboard_getreport (usbdev, data);
+
+      /* Implement a timeout.  */
+      if (grub_get_time_ms () > currtime + timeout)
+       break;
+    }
+  while (err);
+
+  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,
+    .getkeystatus = grub_usb_keyboard_getkeystatus,
     .next = 0
   };
 

-- 
Colin Watson                                       address@hidden




reply via email to

[Prev in Thread] Current Thread [Next in Thread]