diff --git a/src/Include/fg_typedefs.h b/src/Include/fg_typedefs.h
index fa2ba5126..ac9d8892c 100644
--- a/src/Include/fg_typedefs.h
+++ b/src/Include/fg_typedefs.h
@@ -2,8 +2,11 @@
 //  Alterations: Copyright C. Hotchkiss 1996
 //
 // $Log$
-// Revision 1.1  1999/06/17 18:07:30  curt
-// Initial revision
+// Revision 1.2  2001/05/16 21:27:59  curt
+// Added David Megginson's patch for reconfigurable keyboard bindings.
+//
+// Revision 1.1.1.1  1999/06/17 18:07:30  curt
+// Start of 0.7.x branch
 //
 // Revision 1.2  1999/04/22 18:45:42  curt
 // Borland tweaks.
@@ -49,8 +52,8 @@
 //    any application include files.
 */
 
-#if !defined(_TYPEDEFS)
-#define _TYPEDEFS
+#ifndef _FG_TYPEDEFS
+#define _FG_TYPEDEFS
 
 //
 //    Define the types to be used to manipulate 8-, 16-, and 32-bit
@@ -81,32 +84,6 @@ typedef float          FLOAT ;   // 32-bit floating point data
 typedef double         DOUBLE ;  // 64-bit floating point data
 typedef long double    LDOUBLE ; // 80-bit floating point data
 
-#ifndef __cplusplus
-typedef int bool;
-typedef int BOOL;
-typedef int Bool;
-#else
-#ifndef WIN32
-#define BOOL int
-#endif
-#endif
-
-#define Bool int
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#ifndef true          // C++ defines bool, true and false.
-#define true TRUE
-#define false FALSE
-#endif
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
 typedef void(*VFNPTR)   ( void );
 typedef void(*VFNINTPTR)( int  );
 typedef int (*FNPTR)    ( void );
@@ -115,6 +92,4 @@ typedef int (*FNUIPTR)  ( UINT );
 typedef double( *DBLFNPTR)( void );
 typedef float( *FLTFNPTR)( void );
 
-#endif
-
-  /* !defined(_TYPEDEFS) */
+#endif // _FG_TYPEDEFS
diff --git a/src/Main/keyboard.cxx b/src/Main/keyboard.cxx
index 4b8d6556e..df0ca50f6 100644
--- a/src/Main/keyboard.cxx
+++ b/src/Main/keyboard.cxx
@@ -76,12 +76,140 @@
 extern void fgReshape( int width, int height );
 
 
-// Handle keyboard events
+#ifdef BOOL
+#error A sloppy coder has defined BOOL as a macro!
+#undef BOOL
+#endif
+
+
+/**
+ * Fire a user-defined key binding.
+ *
+ * <p>This function is temporary; eventually, all of the keyboard,
+ * joystick, and mouse support should migrate into a common Input
+ * module.</p>
+ *
+ * @param binding The property node for the binding.
+ */
+static void
+doBinding (const SGPropertyNode * binding)
+{
+  const string &action = binding->getStringValue("action", "");
+  const string &control = binding->getStringValue("control", "");
+  bool repeatable = binding->getBoolValue("repeatable", false);
+  int step = binding->getIntValue("step", 0.0);
+
+  if (control == "") {
+    SG_LOG(SG_INPUT, SG_ALERT, "No control specified for key "
+	   << binding->getIndex());
+    return;
+  }
+
+  else if (action == "") {
+    SG_LOG(SG_INPUT, SG_ALERT, "No action specified for key "
+	   << binding->getIndex());
+    return;
+  }
+
+  else if (action == "switch") {
+    SG_LOG(SG_INPUT, SG_INFO, "Toggling value of " << control);
+    fgSetBool(control, !fgGetBool(control));
+  }
+
+  else if (action == "adjust") {
+    const SGValue * step = binding->getValue("value");
+    if (step == 0) {
+      SG_LOG(SG_INPUT, SG_ALERT, "No step supplied for adjust action for key "
+	     << binding->getIndex());
+      return;
+    }
+    SGValue * target = fgGetValue(control, true);
+				// Use the target's type...
+    switch (target->getType()) {
+    case SGValue::BOOL:
+    case SGValue::INT:
+      target->setIntValue(target->getIntValue() + step->getIntValue());
+      break;
+    case SGValue::LONG:
+      target->setLongValue(target->getLongValue() + step->getLongValue());
+      break;
+    case SGValue::FLOAT:
+      target->setFloatValue(target->getFloatValue() + step->getFloatValue());
+      break;
+    case SGValue::DOUBLE:
+    case SGValue::UNKNOWN:	// treat unknown as a double
+      target->setDoubleValue(target->getDoubleValue()
+			     + step->getDoubleValue());
+      break;
+    case SGValue::STRING:
+      SG_LOG(SG_INPUT, SG_ALERT, "Failed attempt to adjust string property "
+	     << control);
+      break;
+    }
+  }
+
+  else if (action == "assign") {
+    const SGValue * value = binding->getValue("value");
+    if (value == 0) {
+      SG_LOG(SG_INPUT, SG_ALERT, "No value supplied for assign action for key "
+	     << binding->getIndex());
+      return;
+    }
+    SGValue * target = fgGetValue(control, true);
+				// Use the target's type...
+    switch (target->getType()) {
+    case SGValue::BOOL:
+      target->setBoolValue(value->getBoolValue());
+      break;
+    case SGValue::INT:
+      target->setIntValue(value->getIntValue());
+      break;
+    case SGValue::LONG:
+      target->setLongValue(value->getLongValue());
+      break;
+    case SGValue::FLOAT:
+      target->setFloatValue(value->getFloatValue());
+      break;
+    case SGValue::DOUBLE:
+      target->setDoubleValue(value->getDoubleValue());
+      break;
+    case SGValue::STRING:
+      target->setStringValue(value->getStringValue());
+      break;
+    case SGValue::UNKNOWN:
+      target->setUnknownValue(value->getStringValue());
+      break;
+    }
+  }
+
+  else {
+    SG_LOG(SG_INPUT, SG_ALERT, "Unknown action " << action
+	   << " for key " << binding->getIndex());
+  }
+}
+
+
+/**
+ * Keyboard event handler for Glut.
+ *
+ * @param k The integer value for the key pressed.
+ * @param x (unused)
+ * @param y (unused)
+ */
 void GLUTkey(unsigned char k, int x, int y) {
     float fov, tmp;
     static bool winding_ccw = true;
     int speed;
 
+				// First, check for a user override.
+    const SGPropertyNode * binding = globals->get_props()
+      ->getNode("/input/keyboard/", true)->getChild("key", int(k));
+    if (binding != 0) {
+      doBinding(binding);
+      return;
+    }
+
+				// Use the old, default actions.
     FGInterface *f = current_aircraft.fdm_state;
     FGViewer *v = globals->get_current_view();