]> Joshua Wise's Git repositories - netwatch.git/blobdiff - cs410/keyhelp.c
First pass of 410watch UI code.
[netwatch.git] / cs410 / keyhelp.c
diff --git a/cs410/keyhelp.c b/cs410/keyhelp.c
new file mode 100644 (file)
index 0000000..98748de
--- /dev/null
@@ -0,0 +1,655 @@
+/**
+ * The 15-410 reference kernel keyboard handling code.
+ *
+ * @author Steve Muckle <smuckle@andrew.cmu.edu>
+ *
+ * @author Edited by zra for the 2003-2004 season.
+ *
+ * @author Edited by mpa for spring 2004
+ *
+ * @author Rewritten by nwf for spring 2007.
+ *
+ * Functions for turning keyboard scancodes
+ * into chars.
+ *
+ * Notice that we use Scancode Set 1
+ */
+/*@{*/
+
+#include "keyhelp.h"
+
+/**
+ * This is returned as the upper bits of the result of
+ * process_scancode and may be interrogated more readily by
+ * the KH_ macros in keyhelp.h
+ *
+ * WARNING:
+ * The bottom bits overlap with the KH_RESULT_ codes in the
+ * return value.
+ */
+static short key_state = 0;
+
+  /** Currently processing a PRINT SCREEN BREAK sequence */
+#define KH_PRSCR_UP_SCAN    0x0008
+  /** Currently processing a PRINT SCREEN MAKE sequence */
+#define KH_PRSCR_DOWN_SCAN  0x0004
+  /** Currently processing a PAUSE/BREAK (MAKE) sequence */
+#define KH_PAUSE_SCAN       0x0002
+  /** Currently processing an extended sequence (E0 prefix) */
+#define KH_EXTENDED_SCAN    0x0001
+static short key_internal_state = 0;
+
+static int key_sequence = 0;
+
+#define KHS_SHIFT_CORE (key_state & (KH_LSHIFT_KEY | KH_RSHIFT_KEY)) 
+#define KHS_CTL_CORE (key_state & (KH_LCONTROL_KEY | KH_RCONTROL_KEY)) 
+
+#define KHS_SHIFT(c,r,s,u) \
+  { c = KHS_SHIFT_CORE ? s : u; r = u; }
+#define KHS_SHIFTCTL(c,r,cc,s,u) \
+  { c = KHS_CTL_CORE ? cc : (KHS_SHIFT_CORE ? s : u); r = u; }
+#define KHS_SHIFTCAPSCTL(c,r,cc,s,u) \
+  { c = KHS_CTL_CORE ? cc : (((KHS_SHIFT_CORE || (key_state & KH_CAPS_LOCK)) && \
+    !(KHS_SHIFT_CORE && (key_state & KH_CAPS_LOCK))) ? s : u) ; r = u; }
+
+/**
+ * This function performs the mapping
+ * from simple scancodes to chars.
+ *
+ * @param scancode a simple scancode.
+ * @param pressed 0 if released, nonzero if pressed.
+ *
+ * @return A partially constructed kh_type.
+ */
+static kh_type
+process_simple_scan(int scancode, int pressed)
+{
+  unsigned char code = 0x80;
+  unsigned char rcode = 0x80;
+  kh_type res = 0;
+
+  switch(scancode & 0x7F)
+  {
+  case 0x1:
+    /* Escape key. */
+    rcode = code = 0x1B;
+    break;
+  case 0x2:
+    /* 1 or ! */
+    KHS_SHIFT(code, rcode, '!', '1');
+    break;
+  case 0x3:
+    /* 2 or @ */
+    KHS_SHIFTCTL(code, rcode, 0x00, '@', '2');
+    break;
+  case 0x4:
+    /* 3 or # */
+    KHS_SHIFT(code, rcode, '#', '3');
+    break;
+  case 0x5:
+    /* 4 or $ */
+    KHS_SHIFT(code, rcode, '$', '4');
+    break;
+  case 0x6:
+    /* 5 or % */
+    KHS_SHIFT(code, rcode, '%', '5');
+    break;
+  case 0x7:
+    /* 6 or ^ */
+    KHS_SHIFTCTL(code, rcode, 0x1E, '^', '6');
+    break;
+  case 0x8:
+    /* 7 or & */
+    KHS_SHIFT(code, rcode, '&', '7');
+    break;
+  case 0x9:
+    /* 8 or * */
+    KHS_SHIFT(code, rcode, '*', '8');
+    break;
+  case 0xA:
+    /* 9 or ( */
+    KHS_SHIFT(code, rcode, '(', '9');
+    break;
+  case 0xB:
+    /* 0 or ) */
+    KHS_SHIFT(code, rcode, ')', '0');
+    break;
+  case 0xC:
+    /* - or _ */
+    KHS_SHIFTCTL(code, rcode, 0x1F, '_', '-');
+    break;
+  case 0xD:
+    /* = or + */
+    KHS_SHIFT(code, rcode, '+', '=');
+    break;
+  case 0xE:
+    /* Backspace key. */
+    rcode = code = '\b';
+    break;
+  case 0xF:
+    /* Tab key. */
+    rcode = code = '\t';
+    break;
+  case 0x10:
+    /* q or Q. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x11, 'Q', 'q');
+    break;
+  case 0x11:
+    /* w or W. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x17, 'W', 'w');
+    break;
+  case 0x12:
+    /* e or E. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x05, 'E', 'e');
+    break;
+  case 0x13:
+    /* r or R. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x12, 'R', 'r');
+    break;
+  case 0x14:
+    /* t or T. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x14, 'T', 't');
+    break;
+  case 0x15:
+    /* y or Y. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x19, 'Y', 'y');
+    break;
+  case 0x16:
+    /* u or U. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x15, 'U', 'u');
+    break;
+  case 0x17:
+    /* i or I. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x09, 'I', 'i');
+    break;
+  case 0x18:
+    /* o or O. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0F, 'O', 'o');
+    break;
+  case 0x19:
+    /* p or P. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x10, 'P', 'p');
+    break;
+  case 0x1A:
+    /* [ or {. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x1B, '{', '[');
+    break;
+  case 0x1B:
+    /* ] or }. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x1D, '}', ']');
+    break;
+  case 0x1C:
+    /* Enter key. */
+    rcode=code='\n';
+    break;
+  case 0x1D:
+    if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 0))
+    {
+      /* Stage 1 of a pause sequence */
+      key_sequence++;
+      return 0;
+    } else {
+      key_internal_state &= ~KH_PAUSE_SCAN;
+      key_sequence = 0;
+    }
+    rcode=KHE_LCTL;
+    if(pressed)
+      key_state |= KH_LCONTROL_KEY;
+    else
+      key_state &= ~KH_LCONTROL_KEY;
+    break;
+  case 0x1E:
+    /* a or A. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x01, 'A', 'a');
+    break;
+  case 0x1F:
+    /* s or S. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x13, 'S', 's');
+    break;
+  case 0x20:
+    /* d or D. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x04, 'D', 'd');
+    break;
+  case 0x21:
+    /* f or F. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x06, 'F', 'f');
+    break;
+  case 0x22:
+    /* g or G. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x07, 'G', 'g');
+    break;
+  case 0x23:
+    /* h or H. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x08, 'H', 'h');
+    break;
+  case 0x24:
+    /* j or J. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0A, 'J', 'j');
+    break;
+  case 0x25:
+    /* k or K. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0B, 'K', 'k');
+    break;
+  case 0x26:
+    /* l or L. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0C, 'L', 'l');
+    break;
+  case 0x27:
+    /* ; or :. */
+    KHS_SHIFT(code, rcode, ':', ';');
+    break;
+  case 0x28:
+    /* ' or " */
+    KHS_SHIFT(code, rcode, '\"', '\'');
+    break;
+  case 0x29:
+    KHS_SHIFT(code, rcode, '~', '`');
+    break;
+  case 0x2A:
+    rcode = KHE_LSHIFT;
+    if(pressed)
+      key_state |= KH_LSHIFT_KEY;
+    else
+      key_state &= ~KH_LSHIFT_KEY;
+    break;
+  case 0x2B:
+    /* \ or |. */
+    KHS_SHIFTCTL(code, rcode, 0x1C, '|', '\\');
+    break;
+  case 0x2C:
+    /* z or Z. */ 
+    KHS_SHIFTCAPSCTL(code, rcode, 0x1A, 'Z', 'z');
+    break;
+  case 0x2D:
+    /* x or X. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x18, 'X', 'x');
+    break;
+  case 0x2E:
+    /* c or C. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x03, 'C', 'c');
+    break;
+  case 0x2F:
+    /* v or V. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x16, 'V', 'v');
+    break;
+  case 0x30:
+    /* b or B. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x02, 'B', 'b');
+    break;
+  case 0x31:
+    /* n or N. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0E, 'N', 'n');
+    break;
+  case 0x32:
+    /* m or M. */
+    KHS_SHIFTCAPSCTL(code, rcode, 0x0D, 'M', 'm');
+    break;
+  case 0x33:
+    /* , or <. */
+    KHS_SHIFT(code, rcode, '<', ',');
+    break;
+  case 0x34:
+    /* . or >. */
+    KHS_SHIFT(code, rcode, '>', '.');
+    break;
+  case 0x35:
+    /* / or ? */
+    KHS_SHIFT(code, rcode, '?', '/');
+    break;
+  case 0x36:
+    rcode = KHE_RSHIFT;
+    if(pressed)
+      key_state |= KH_RSHIFT_KEY;
+    else
+      key_state &= ~KH_RSHIFT_KEY;
+    break;
+  case 0x37:
+    /* NP * */
+    rcode = code = '*';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x38:
+    rcode = KHE_LALT;
+    if(pressed)
+      key_state |= KH_LALT_KEY;
+    else
+      key_state &= ~KH_LALT_KEY;
+    break;
+  case 0x39:
+    /* Space bar. */
+    rcode = code =' ';
+    break;
+  case 0x3A:
+    rcode = KHE_CAPSLOCK;
+    if(pressed)
+    {
+      if(key_state & KH_CAPS_LOCK)
+        key_state &= ~KH_CAPS_LOCK;
+      else
+        key_state |= KH_CAPS_LOCK;
+    }
+    break;
+  case 0x3B:
+    /* F1 key. */
+    rcode = code = KHE_F1;
+    break;
+  case 0x3C:
+    /* F2 key. */
+    rcode = code = KHE_F2;
+    break;
+  case 0x3D:
+    /* F3 key. */
+    rcode = code = KHE_F3;
+    break;
+  case 0x3E:
+    /* F4 key. */
+    rcode = code = KHE_F4;
+    break;
+  case 0x3F:
+    /* F5 key. */
+    rcode = code = KHE_F5;
+    break;
+  case 0x40:
+    /* F6 key. */
+    rcode = code = KHE_F6;
+    break;
+  case 0x41:
+    /* F7 key. */
+    rcode = code = KHE_F7;
+    break;
+  case 0x42:
+    /* F8 key. */
+    rcode = code = KHE_F8;
+    break;
+  case 0x43:
+    /* F9 key. */
+    rcode = code = KHE_F9;
+    break;
+  case 0x44:
+    /* F10 key. */
+    rcode = code = KHE_F10;
+    break;
+  case 0x45:
+    if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 1))
+    {
+      /* Stage 2 of a pause sequence */
+      key_sequence++;
+      return 0;
+    } else {
+      key_internal_state &= ~KH_PAUSE_SCAN;
+      key_sequence = 0;
+    }
+    rcode = KHE_NUMLOCK;
+    if(pressed)
+    {
+      if(key_state & KH_NUM_LOCK)
+        key_state &= ~KH_NUM_LOCK;
+      else
+        key_state |= KH_NUM_LOCK;
+    }
+    break;
+  case 0x47:
+    rcode = code = '7';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x48:
+    rcode = code = '8';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x49:
+    rcode = code = '9';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4A:
+    rcode = code = '-';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4B:
+    rcode = code = '4';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4C:
+    rcode = code = '5';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4D:
+    rcode = code = '6';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4E:
+    rcode = code = '+';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x4F:
+    rcode = code = '1';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x50:
+    rcode = code = '2';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x51:
+    rcode = code = '3';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x52:
+    rcode = code = '0';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x53:
+    rcode = code = '.';
+    res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+    break;
+  case 0x57:
+    /* F11 key. */
+    rcode = code = KHE_F11;
+    break;
+  case 0x58:
+    /* F12 key. */
+    rcode = code = KHE_F12;
+    break;
+  case 0xE1 & 0x7F:
+    if(!(key_internal_state & KH_PAUSE_SCAN))
+    {
+      /* Stage 0 of a pause sequence */
+      key_internal_state |= KH_PAUSE_SCAN;
+      key_sequence = 0;
+      return 0;
+    } else if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 2)) {
+      key_sequence++;
+      return 0;
+    } else {
+      key_internal_state &= ~KH_PAUSE_SCAN;
+      key_sequence = 0;
+    }
+    /* FALLTHROUGH */
+  default:
+    rcode = code = KHE_UNDEFINED;
+    break;
+  }
+
+  if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
+    res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+  else
+    code = 0x00;
+
+  return res | (code << KH_CHAR_SHIFT)
+            | (rcode << KH_RAWCHAR_SHIFT)
+            | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
+}
+
+/**
+ * Processes extended scan codes.  Notably, this includes
+ * the arrow keys as well as some of the more unusual keys
+ * on the keyboard.
+ *
+ * @param keypress the extended scancode.
+ * @param 0 if released. non-zero if pressed.
+ *
+ * @return A partially constructed kh_type.
+ */
+kh_type
+process_extended_scan(int keypress, int pressed)
+{
+  unsigned char code = 0x80;
+  unsigned char rcode = 0x80;
+  kh_type res = 0;
+
+  /* Intermediate states in multiple byte scancodes should return
+   * zero from this function, rather than returning a RESULT code.
+   */
+
+  switch(keypress & 0x7F)
+  {
+    case 0x1C:
+      /* NP '\n' */
+      rcode = code = '\n';
+      res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+      break;
+    case 0x1D:
+      /* Right control key */
+      rcode = KHE_RCTL;
+      if(pressed)
+        key_state |= KH_RCONTROL_KEY;
+      else
+        key_state &= ~KH_RCONTROL_KEY;
+      break;
+    case 0x2A:
+      /* Stage 0 of PRINT SCREEN MAKE and Stage 1 of PRINT SCREEN BREAK */
+      if(key_internal_state & KH_PRSCR_UP_SCAN)
+      {
+        rcode = code = KHE_PRINT_SCREEN;
+        key_internal_state &= ~KH_PRSCR_UP_SCAN;
+      } else if (!(key_internal_state & KH_PRSCR_UP_SCAN)) {
+        key_internal_state |= KH_PRSCR_DOWN_SCAN;
+        key_internal_state &= ~KH_EXTENDED_SCAN;
+        return 0;
+      } else {
+        rcode = code = KHE_UNDEFINED;
+      }
+      break;
+    case 0x35:
+      /* NP / */
+      rcode = code = '/';
+      res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
+      break;
+    case 0x37:
+      /* Stage 1 of PRINT SCREEN MAKE and Stage 0 of PRINT SCREEN BREAK */
+      if(key_internal_state & KH_PRSCR_DOWN_SCAN)
+      {
+        rcode = code = KHE_PRINT_SCREEN;
+        key_internal_state &= ~KH_PRSCR_DOWN_SCAN;
+      } else if (!(key_internal_state & KH_PRSCR_DOWN_SCAN)) {
+        key_internal_state |= KH_PRSCR_UP_SCAN;
+        key_internal_state &= ~KH_EXTENDED_SCAN;
+        return 0;
+      } else {
+        rcode = code = KHE_UNDEFINED;
+      }
+      break;
+    case 0x38:
+      /* Right alt key */
+      rcode = KHE_RALT;
+      if(pressed)
+        key_state |= KH_RALT_KEY;
+      else
+        key_state &= ~KH_RALT_KEY;
+      break;
+    case 0x48:
+      /* UP */
+      rcode = code=KHE_ARROW_UP;
+      break;
+    case 0x4b:
+      /* LEFT */
+      rcode = code=KHE_ARROW_LEFT;
+      break;
+    case 0x4d:
+      /* RIGHT */
+      rcode = code=KHE_ARROW_RIGHT;
+      break;
+    case 0x50:
+      /* DOWN */
+      rcode = code = KHE_ARROW_DOWN;
+      break;
+    case 0x53:
+      /* DEL */
+      rcode = code = 0x7F;
+      break;
+    default:
+      rcode = code = KHE_UNDEFINED;
+      break;
+  }
+
+  key_internal_state &= ~KH_EXTENDED_SCAN;
+
+  if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
+    res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+  else
+    code = 0x00;
+
+  return res | (code << KH_CHAR_SHIFT)
+            | (rcode << KH_RAWCHAR_SHIFT)
+            | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
+}
+
+  /** The entrypoint to the keyboard processing library.
+   *
+   * @param keypress A raw scancode as returned by the keyboard hardware.
+   * @return A kh_type indicating the keyboard modifier key states, result
+   *         modifier bits, and potentially ASCII/410 Upper Code Plane
+   *         translations.
+   */
+kh_type process_scancode(int keypress) {
+  kh_type res;
+  int pressed = !(keypress & 0x80);
+  int keycode = keypress & 0x7F;
+  
+  if (key_internal_state & KH_EXTENDED_SCAN)
+    res = process_extended_scan(keycode, pressed);
+  else
+  {
+    switch(keypress & 0xFF)
+    {
+      case 0x9D:
+        if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 3))
+        {
+          key_sequence++;
+          return 0;
+        } else {
+          key_internal_state &= ~KH_PAUSE_SCAN;
+          key_sequence = 0;
+        }
+        goto deflt;
+      case 0xC5:
+        if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 4))
+        {
+          key_internal_state &= ~KH_PAUSE_SCAN;
+          /* Pause sequence completed */
+          res = (KHE_PAUSE << KH_CHAR_SHIFT)
+                | (KHE_PAUSE << KH_RAWCHAR_SHIFT)
+                | (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
+          break;
+        }
+        key_internal_state &= ~KH_PAUSE_SCAN;
+        key_sequence = 0;
+        goto deflt;
+      case 0xE0:
+        key_internal_state |= KH_EXTENDED_SCAN;
+        /* Return no result for this intermediate state */
+        return key_state << KH_STATE_SHIFT;
+      default:
+deflt:
+        key_internal_state &= ~(KH_PRSCR_UP_SCAN | KH_PRSCR_DOWN_SCAN);
+        res = process_simple_scan(keycode, pressed);
+    }
+  }
+
+  if(pressed)
+    res |= KH_RESULT_MAKE << KH_RMODS_SHIFT;
+
+  res |= (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT;
+
+  return res;
+}
+
+/*@}*/
This page took 0.036741 seconds and 4 git commands to generate.