]> git.mxchange.org Git - flightgear.git/blobdiff - src/Input/input.cxx
Added static port system and a new altimeter model connected to it.
[flightgear.git] / src / Input / input.cxx
index 7dfbc57b49902779a4920e35ef0784bd404424f1..93cad1dbadd33cdc0675bbe208d27b01402ce390 100644 (file)
@@ -110,8 +110,8 @@ FGBinding::read (const SGPropertyNode * node)
   }
 
   _command_name = node->getStringValue("command", "");
-  if (_command_name == "") {
-    SG_LOG(SG_INPUT, SG_ALERT, "No command supplied for binding.");
+  if (_command_name.empty()) {
+    SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
     _command = 0;
     return;
   }
@@ -134,7 +134,7 @@ FGBinding::fire () const
 {
   if (test()) {
     if (_command == 0) {
-      SG_LOG(SG_INPUT, SG_ALERT, "No command attached to binding");
+      SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding");
     } else if (!(*_command)(_arg, &_command_state)) {
       SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
             << _command_name);
@@ -142,6 +142,15 @@ FGBinding::fire () const
   }
 }
 
+void
+FGBinding::fire (double offset, double max) const
+{
+  if (test()) {
+    _arg->setDoubleValue("offset", offset/max);
+    fire();
+  }
+}
+
 void
 FGBinding::fire (double setting) const
 {
@@ -182,6 +191,15 @@ FGInput::init ()
 {
   _init_keyboard();
   _init_joystick();
+  _init_mouse();
+
+  glutKeyboardFunc(GLUTkey);
+  glutKeyboardUpFunc(GLUTkeyup);
+  glutSpecialFunc(GLUTspecialkey);
+  glutSpecialUpFunc(GLUTspecialkeyup);
+  glutMouseFunc (GLUTmouse);
+  glutMotionFunc (GLUTmotion);
+  glutPassiveMotionFunc (GLUTmotion);
 }
 
 void
@@ -197,21 +215,22 @@ FGInput::unbind ()
 }
 
 void 
-FGInput::update (int dt)
+FGInput::update (double dt)
 {
   _update_keyboard();
   _update_joystick();
+  _update_mouse();
 }
 
 void
 FGInput::doKey (int k, int modifiers, int x, int y)
 {
-    // SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k
-    //                << " with modifiers " << modifiers );
+  SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
+         << " with modifiers " << modifiers );
 
                                // Sanity check.
   if (k < 0 || k >= MAX_KEYS) {
-    SG_LOG(SG_INPUT, SG_ALERT, "Key value " << k << " out of range");
+    SG_LOG(SG_INPUT, SG_WARN, "Key value " << k << " out of range");
     return;
   }
 
@@ -219,8 +238,8 @@ FGInput::doKey (int k, int modifiers, int x, int y)
 
                                // Key pressed.
   if (modifiers&FG_MOD_UP == 0) {
-    // SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k
-    //         << " with modifiers " << modifiers );
+    SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
+           << " with modifiers " << modifiers );
     if (!b.last_state || b.is_repeatable) {
       const binding_list_t &bindings =
        _find_key_bindings(k, modifiers);
@@ -235,8 +254,8 @@ FGInput::doKey (int k, int modifiers, int x, int y)
 
                                // Key released.
   else {
-    // SG_LOG(SG_INPUT, SG_INFO, "User released key " << k
-    //        << " with modifiers " << modifiers);
+    SG_LOG(SG_INPUT, SG_DEBUG, "User released key " << k
+          << " with modifiers " << modifiers);
     if (b.last_state) {
       const binding_list_t &bindings =
        _find_key_bindings(k, modifiers);
@@ -251,7 +270,7 @@ FGInput::doKey (int k, int modifiers, int x, int y)
 
 
                                // Use the old, default actions.
-  // SG_LOG( SG_INPUT, SG_INFO, "(No user binding.)" );
+  SG_LOG( SG_INPUT, SG_DEBUG, "(No user binding.)" );
   if (modifiers&FG_MOD_UP)
     return;
 
@@ -330,22 +349,110 @@ FGInput::doKey (int k, int modifiers, int x, int y)
     }
 }
 
+void
+FGInput::doMouseClick (int b, int updown, int x, int y)
+{
+  int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
+
+  mouse &m = _mouse_bindings[0];
+  mouse_mode &mode = m.modes[m.current_mode];
+
+                               // Let the property manager know.
+  if (b >= 0 && b < MAX_MOUSE_BUTTONS)
+    m.mouse_button_nodes[b]->setBoolValue(updown == GLUT_DOWN);
+
+                               // Pass on to PUI and the panel if
+                               // requested, and return if one of
+                               // them consumes the event.
+  if (mode.pass_through) {
+    if (puMouse(b, updown, x, y))
+      return;
+    else if ((current_panel != 0) &&
+            current_panel->doMouseAction(b, updown, x, y))
+      return;
+  }
+
+                               // OK, PUI and the panel didn't want the click
+  if (b >= MAX_MOUSE_BUTTONS) {
+    SG_LOG(SG_INPUT, SG_ALERT, "Mouse button " << b
+          << " where only " << MAX_MOUSE_BUTTONS << " expected");
+    return;
+  }
+
+  _update_button(m.modes[m.current_mode].buttons[b], modifiers, 0 != updown, x, y);
+}
+
+void
+FGInput::doMouseMotion (int x, int y)
+{
+  int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
+
+  int xsize = fgGetInt("/sim/startup/xsize", 800);
+  int ysize = fgGetInt("/sim/startup/ysize", 600);
+  mouse &m = _mouse_bindings[0];
+  if (m.current_mode < 0 || m.current_mode >= m.nModes)
+    return;
+  mouse_mode &mode = m.modes[m.current_mode];
+
+                               // Pass on to PUI if requested, and return
+                               // if PUI consumed the event.
+  if (mode.pass_through && puMouse(x, y))
+    return;
+
+                               // OK, PUI didn't want the event,
+                               // so we can play with it.
+  if (x != m.x) {
+    int delta = x - m.x;
+    for (unsigned int i = 0; i < mode.x_bindings[modifiers].size(); i++)
+      mode.x_bindings[modifiers][i]->fire(double(delta), double(xsize));
+  }
+  if (y != m.y) {
+    int delta = y - m.y;
+    for (unsigned int i = 0; i < mode.y_bindings[modifiers].size(); i++)
+      mode.y_bindings[modifiers][i]->fire(double(delta), double(ysize));
+  }
+
+                               // Constrain the mouse if requested
+  if (mode.constrained) {
+    bool need_warp = false;
+    if (x <= 0) {
+      x = xsize - 2;
+      need_warp = true;
+    } else if (x >= (xsize-1)) {
+      x = 1;
+      need_warp = true;
+    }
+
+    if (y <= 0) {
+      y = ysize - 2;
+      need_warp = true;
+    } else if (y >= (ysize-1)) {
+      y = 1;
+      need_warp = true;
+    }
+
+    if (need_warp)
+      glutWarpPointer(x, y);
+  }
+  m.x = x;
+  m.y = y;
+}
 
 void
 FGInput::_init_keyboard ()
 {
                                // TODO: zero the old bindings first.
-  SG_LOG(SG_INPUT, SG_INFO, "Initializing key bindings");
+  SG_LOG(SG_INPUT, SG_DEBUG, "Initializing key bindings");
   SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
   if (key_nodes == 0) {
-    SG_LOG(SG_INPUT, SG_ALERT, "No key bindings (/input/keyboard)!!");
-    return;
+    SG_LOG(SG_INPUT, SG_WARN, "No key bindings (/input/keyboard)!!");
+    key_nodes = fgGetNode("/input/keyboard", true);
   }
   
-  vector<SGPropertyNode *> keys = key_nodes->getChildren("key");
+  vector<SGPropertyNode_ptr> keys = key_nodes->getChildren("key");
   for (unsigned int i = 0; i < keys.size(); i++) {
     int index = keys[i]->getIndex();
-    SG_LOG(SG_INPUT, SG_INFO, "Binding key " << index);
+    SG_LOG(SG_INPUT, SG_DEBUG, "Binding key " << index);
     _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
     _read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE);
   }
@@ -356,45 +463,69 @@ void
 FGInput::_init_joystick ()
 {
                                // TODO: zero the old bindings first.
-  SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick bindings");
+  SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
   SGPropertyNode * js_nodes = fgGetNode("/input/joysticks");
   if (js_nodes == 0) {
-    SG_LOG(SG_INPUT, SG_ALERT, "No joystick bindings (/input/joysticks)!!");
-    return;
+    SG_LOG(SG_INPUT, SG_WARN, "No joystick bindings (/input/joysticks)!!");
+    js_nodes = fgGetNode("/input/joysticks", true);
   }
 
   for (int i = 0; i < MAX_JOYSTICKS; i++) {
-    const SGPropertyNode * js_node = js_nodes->getChild("js", i);
+    SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
     if (js_node == 0) {
-      SG_LOG(SG_INPUT, SG_ALERT, "No bindings for joystick " << i);
-      continue;
+      SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for joystick " << i);
+      js_node = js_nodes->getChild("js", i, true);
     }
     jsJoystick * js = new jsJoystick(i);
     _joystick_bindings[i].js = js;
     if (js->notWorking()) {
-      SG_LOG(SG_INPUT, SG_INFO, "Joystick " << i << " not found");
+      SG_LOG(SG_INPUT, SG_WARN, "Joystick " << i << " not found");
       continue;
+    } else {
+#ifdef FG_PLIB_JOYSTICK_GETNAME
+      bool found_js = false;
+      const char * name = js->getName();
+      SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \""
+            << name << '"');
+      vector<SGPropertyNode_ptr> nodes = js_nodes->getChildren("js-named");
+      for (unsigned int i = 0; i < nodes.size(); i++) {
+       SGPropertyNode_ptr node = nodes[i];
+        vector<SGPropertyNode_ptr> name_nodes = node->getChildren("name");
+        for (unsigned int j = 0; j < name_nodes.size(); j++) {
+            const char * js_name = name_nodes[j]->getStringValue();
+            SG_LOG(SG_INPUT, SG_INFO, "  Trying \"" << js_name << '"');
+            if (!strcmp(js_name, name)) {
+                SG_LOG(SG_INPUT, SG_INFO, "  Found bindings");
+                js_node = node;
+                found_js = true;
+                break;
+            }
+        }
+        if (found_js)
+            break;
+      }
+#endif
     }
 #ifdef WIN32
     JOYCAPS jsCaps ;
     joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
     int nbuttons = jsCaps.wNumButtons;
-    if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS;
+    if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
 #else
-    int nbuttons = MAX_BUTTONS;
+    int nbuttons = MAX_JOYSTICK_BUTTONS;
 #endif
        
     int naxes = js->getNumAxes();
-    if (naxes > MAX_AXES) naxes = MAX_AXES;
+    if (naxes > MAX_JOYSTICK_AXES) naxes = MAX_JOYSTICK_AXES;
     _joystick_bindings[i].naxes = naxes;
     _joystick_bindings[i].nbuttons = nbuttons;
 
-    SG_LOG(SG_INPUT, SG_INFO, "Initializing joystick " << i);
+    SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick " << i);
 
                                // Set up range arrays
-    float minRange[MAX_AXES];
-    float maxRange[MAX_AXES];
-    float center[MAX_AXES];
+    float minRange[MAX_JOYSTICK_AXES];
+    float maxRange[MAX_JOYSTICK_AXES];
+    float center[MAX_JOYSTICK_AXES];
 
                                // Initialize with default values
     js->getMinRange(minRange);
@@ -413,8 +544,8 @@ FGInput::_init_joystick ()
     for (j = 0; j < naxes; j++) {
       const SGPropertyNode * axis_node = js_node->getChild("axis", j);
       if (axis_node == 0) {
-       SG_LOG(SG_INPUT, SG_INFO, "No bindings for axis " << j);
-       continue;
+       SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for axis " << j);
+       axis_node = js_node->getChild("axis", j, true);
       }
       
       axis &a = _joystick_bindings[i].axes[j];
@@ -439,10 +570,10 @@ FGInput::_init_joystick ()
     //
     // Initialize the buttons.
     //
-    char buf[8];
+    char buf[32];
     for (j = 0; j < nbuttons; j++) {
       sprintf(buf, "%d", j);
-      SG_LOG(SG_INPUT, SG_INFO, "Initializing button " << j);
+      SG_LOG(SG_INPUT, SG_DEBUG, "Initializing button " << j);
       _init_button(js_node->getChild("button", j),
                   _joystick_bindings[i].buttons[j],
                   buf);
@@ -455,15 +586,122 @@ FGInput::_init_joystick ()
   }
 }
 
+// 
+// Map of all known GLUT cursor names
+//
+struct {
+  const char * name;
+  int cursor;
+} mouse_cursor_map[] = {
+  { "right-arrow", GLUT_CURSOR_RIGHT_ARROW },
+  { "left-arrow", GLUT_CURSOR_LEFT_ARROW },
+  { "info", GLUT_CURSOR_INFO },
+  { "destroy", GLUT_CURSOR_DESTROY },
+  { "help", GLUT_CURSOR_HELP },
+  { "cycle", GLUT_CURSOR_CYCLE },
+  { "spray", GLUT_CURSOR_SPRAY },
+  { "wait", GLUT_CURSOR_WAIT },
+  { "text", GLUT_CURSOR_TEXT },
+  { "crosshair", GLUT_CURSOR_CROSSHAIR },
+  { "up-down", GLUT_CURSOR_UP_DOWN },
+  { "left-right", GLUT_CURSOR_LEFT_RIGHT },
+  { "top-side", GLUT_CURSOR_TOP_SIDE },
+  { "bottom-side", GLUT_CURSOR_BOTTOM_SIDE },
+  { "left-side", GLUT_CURSOR_LEFT_SIDE },
+  { "right-side", GLUT_CURSOR_RIGHT_SIDE },
+  { "top-left-corner", GLUT_CURSOR_TOP_LEFT_CORNER },
+  { "top-right-corner", GLUT_CURSOR_TOP_RIGHT_CORNER },
+  { "bottom-right-corner", GLUT_CURSOR_BOTTOM_RIGHT_CORNER },
+  { "bottom-left-corner", GLUT_CURSOR_BOTTOM_LEFT_CORNER },
+  { "inherit", GLUT_CURSOR_INHERIT },
+  { "none", GLUT_CURSOR_NONE },
+  { "full-crosshair", GLUT_CURSOR_FULL_CROSSHAIR },
+  { 0, 0 }
+};
+
+
+
+void
+FGInput::_init_mouse ()
+{
+  SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse bindings");
+
+  SGPropertyNode * mouse_nodes = fgGetNode("/input/mice");
+  if (mouse_nodes == 0) {
+    SG_LOG(SG_INPUT, SG_WARN, "No mouse bindings (/input/mice)!!");
+    mouse_nodes = fgGetNode("/input/mice", true);
+  }
+
+  int j;
+  for (int i = 0; i < MAX_MICE; i++) {
+    SGPropertyNode * mouse_node = mouse_nodes->getChild("mouse", i, true);
+    mouse &m = _mouse_bindings[i];
+
+                               // Grab node pointers
+    char buf[64];
+    sprintf(buf, "/devices/status/mice/mouse[%d]/mode", i);
+    m.mode_node = fgGetNode(buf, true);
+    m.mode_node->setIntValue(0);
+    for (j = 0; j < MAX_MOUSE_BUTTONS; j++) {
+      sprintf(buf, "/devices/status/mice/mouse[%d]/button[%d]", i, j);
+      m.mouse_button_nodes[j] = fgGetNode(buf, true);
+      m.mouse_button_nodes[j]->setBoolValue(false);
+    }
+
+                               // Read all the modes
+    m.nModes = mouse_node->getIntValue("mode-count", 1);
+    m.modes = new mouse_mode[m.nModes];
+
+    for (int j = 0; j < m.nModes; j++) {
+      int k;
+
+                               // Read the mouse cursor for this mode
+      SGPropertyNode * mode_node = mouse_node->getChild("mode", j, true);
+      const char * cursor_name =
+       mode_node->getStringValue("cursor", "inherit");
+      m.modes[j].cursor = GLUT_CURSOR_INHERIT;
+      for (k = 0; mouse_cursor_map[k].name != 0; k++) {
+       if (!strcmp(mouse_cursor_map[k].name, cursor_name)) {
+         m.modes[j].cursor = mouse_cursor_map[k].cursor;
+         break;
+       }
+      }
+
+                               // Read other properties for this mode
+      m.modes[j].constrained = mode_node->getBoolValue("constrained", false);
+      m.modes[j].pass_through = mode_node->getBoolValue("pass-through", false);
+
+                               // Read the button bindings for this mode
+      m.modes[j].buttons = new button[MAX_MOUSE_BUTTONS];
+      char buf[32];
+      for (k = 0; k < MAX_MOUSE_BUTTONS; k++) {
+       sprintf(buf, "mouse button %d", k);
+       SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse button " << k);
+       _init_button(mode_node->getChild("button", k),
+                    m.modes[j].buttons[k],
+                    buf);
+      }
+
+                               // Read the axis bindings for this mode
+      _read_bindings(mode_node->getChild("x-axis", 0, true),
+                    m.modes[j].x_bindings,
+                    FG_MOD_NONE);
+      _read_bindings(mode_node->getChild("y-axis", 0, true),
+                    m.modes[j].y_bindings,
+                    FG_MOD_NONE);
+    }
+  }
+}
+
 
-inline void
+void
 FGInput::_init_button (const SGPropertyNode * node,
                       button &b,
                       const string name)
 {      
-  if (node == 0)
-    SG_LOG(SG_INPUT, SG_INFO, "No bindings for button " << name);
-  else {
+  if (node == 0) {
+    SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for button " << name);
+  else {
     b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable);
     
                // Get the bindings for the button
@@ -485,7 +723,7 @@ FGInput::_update_joystick ()
   int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
   int buttons;
   // float js_val, diff;
-  float axis_values[MAX_AXES];
+  float axis_values[MAX_JOYSTICK_AXES];
 
   int i;
   int j;
@@ -507,10 +745,10 @@ FGInput::_update_joystick ()
                                // is unchanged; only a change in
                                // position fires the bindings.
       if (fabs(axis_values[j] - a.last_value) > a.tolerance) {
-//     SG_LOG(SG_INPUT, SG_INFO, "Axis " << j << " has moved");
+//     SG_LOG(SG_INPUT, SG_DEBUG, "Axis " << j << " has moved");
        SGPropertyNode node;
        a.last_value = axis_values[j];
-//     SG_LOG(SG_INPUT, SG_INFO, "There are "
+//     SG_LOG(SG_INPUT, SG_DEBUG, "There are "
 //            << a.bindings[modifiers].size() << " bindings");
        for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++)
          a.bindings[modifiers][k]->fire(axis_values[j]);
@@ -520,40 +758,62 @@ FGInput::_update_joystick ()
       if (a.low.bindings[modifiers].size())
        _update_button(_joystick_bindings[i].axes[j].low,
                       modifiers,
-                      axis_values[j] < a.low_threshold);
+                      axis_values[j] < a.low_threshold,
+                      -1, -1);
       
       if (a.high.bindings[modifiers].size())
        _update_button(_joystick_bindings[i].axes[j].high,
                       modifiers,
-                      axis_values[j] > a.high_threshold);
+                      axis_values[j] > a.high_threshold,
+                      -1, -1);
     }
 
                                // Fire bindings for the buttons.
     for (j = 0; j < _joystick_bindings[i].nbuttons; j++) {
       _update_button(_joystick_bindings[i].buttons[j],
                     modifiers,
-                    (buttons & (1 << j)) > 0);
+                    (buttons & (1 << j)) > 0,
+                    -1, -1);
     }
   }
 }
 
+void
+FGInput::_update_mouse ()
+{
+  mouse &m = _mouse_bindings[0];
+  int mode =  m.mode_node->getIntValue();
+  if (mode != m.current_mode) {
+    m.current_mode = mode;
+    if (mode >= 0 && mode < m.nModes) {
+      glutSetCursor(m.modes[mode].cursor);
+      m.x = fgGetInt("/sim/startup/xsize", 800) / 2;
+      m.y = fgGetInt("/sim/startup/ysize", 600) / 2;
+      glutWarpPointer(m.x, m.y);
+    } else {
+      SG_LOG(SG_INPUT, SG_DEBUG, "Mouse mode " << mode << " out of range");
+      glutSetCursor(GLUT_CURSOR_INHERIT);
+    }
+  }
+}
 
 void
-FGInput::_update_button (button &b, int modifiers, bool pressed)
+FGInput::_update_button (button &b, int modifiers, bool pressed,
+                        int x, int y)
 {
   if (pressed) {
                                // The press event may be repeated.
     if (!b.last_state || b.is_repeatable) {
-      // SG_LOG( SG_INPUT, SG_INFO, "Button has been pressed" );
+      SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
       for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
-       b.bindings[modifiers][k]->fire();
+       b.bindings[modifiers][k]->fire(x, y);
     }
   } else {
                                // The release event is never repeated.
     if (b.last_state) {
-      // SG_LOG( SG_INPUT, SG_INFO, "Button has been released" );
+      SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
       for (unsigned int k = 0; k < b.bindings[modifiers|FG_MOD_UP].size(); k++)
-       b.bindings[modifiers|FG_MOD_UP][k]->fire();
+       b.bindings[modifiers|FG_MOD_UP][k]->fire(x, y);
     }
   }
          
@@ -566,10 +826,10 @@ FGInput::_read_bindings (const SGPropertyNode * node,
                         binding_list_t * binding_list,
                         int modifiers)
 {
-  SG_LOG(SG_INPUT, SG_INFO, "Reading all bindings");
-  vector<const SGPropertyNode *> bindings = node->getChildren("binding");
+  SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
+  vector<SGPropertyNode_ptr> bindings = node->getChildren("binding");
   for (unsigned int i = 0; i < bindings.size(); i++) {
-    SG_LOG(SG_INPUT, SG_INFO, "Reading binding "
+    SG_LOG(SG_INPUT, SG_DEBUG, "Reading binding "
           << bindings[i]->getStringValue("command"));
     binding_list[modifiers].push_back(new FGBinding(bindings[i]));
   }
@@ -678,8 +938,55 @@ FGInput::joystick::joystick ()
 FGInput::joystick::~joystick ()
 {
 //   delete js;
-//   delete[] axes;
-//   delete[] buttons;
+  delete[] axes;
+  delete[] buttons;
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGInput::mouse_mode
+////////////////////////////////////////////////////////////////////////
+
+FGInput::mouse_mode::mouse_mode ()
+  : cursor(GLUT_CURSOR_INHERIT),
+    constrained(false),
+    pass_through(false),
+    buttons(0)
+{
+}
+
+FGInput::mouse_mode::~mouse_mode ()
+{
+                               // FIXME: memory leak
+//   for (int i = 0; i < FG_MOD_MAX; i++) {
+//     int j;
+//     for (j = 0; i < x_bindings[i].size(); j++)
+//       delete bindings[i][j];
+//     for (j = 0; j < y_bindings[i].size(); j++)
+//       delete bindings[i][j];
+//   }
+  delete [] buttons;
+}
+
+
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGInput::mouse
+////////////////////////////////////////////////////////////////////////
+
+FGInput::mouse::mouse ()
+  : x(-1),
+    y(-1),
+    nModes(1),
+    current_mode(0),
+    modes(0)
+{
+}
+
+FGInput::mouse::~mouse ()
+{
+  delete [] modes;
 }
 
 
@@ -708,68 +1015,49 @@ static inline int get_mods ()
 }
 
 
-/**
- * Key-down event handler for Glut.
- *
- * <p>Pass the value on to the FGInput module unless PUI wants it.</p>
- *
- * @param k The integer value for the key pressed.
- * @param x (unused)
- * @param y (unused)
- */
-void GLUTkey(unsigned char k, int x, int y)
+\f
+////////////////////////////////////////////////////////////////////////
+// GLUT C callbacks.
+////////////////////////////////////////////////////////////////////////
+
+void
+GLUTkey(unsigned char k, int x, int y)
 {
                                // Give PUI a chance to grab it first.
   if (!puKeyboard(k, PU_DOWN))
     current_input.doKey(k, get_mods(), x, y);
 }
 
-
-/**
- * Key-up event handler for GLUT.
- *
- * <p>PUI doesn't use this, so always pass it to the input manager.</p>
- *
- * @param k The integer value for the key pressed.
- * @param x (unused)
- * @param y (unused)
- */
-void GLUTkeyup(unsigned char k, int x, int y)
+void
+GLUTkeyup(unsigned char k, int x, int y)
 {
   current_input.doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y);
 }
 
-
-/**
- * Special key-down handler for Glut.
- *
- * <p>Pass the value on to the FGInput module unless PUI wants it.
- * The key value will have 256 added to it.</p>
- *
- * @param k The integer value for the key pressed (will have 256 added
- * to it).
- * @param x (unused)
- * @param y (unused)
- */
-void GLUTspecialkey(int k, int x, int y)
+void
+GLUTspecialkey(int k, int x, int y)
 {
                                // Give PUI a chance to grab it first.
   if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN))
     current_input.doKey(k + 256, get_mods(), x, y);
 }
 
-
-/**
- * Special key-up handler for Glut.
- *
- * @param k The integer value for the key pressed (will have 256 added
- * to it).
- * @param x (unused)
- * @param y (unused)
- */
-void GLUTspecialkeyup(int k, int x, int y)
+void
+GLUTspecialkeyup(int k, int x, int y)
 {
   current_input.doKey(k + 256, get_mods()|FGInput::FG_MOD_UP, x, y);
 }
 
+void
+GLUTmouse (int button, int updown, int x, int y)
+{
+  current_input.doMouseClick(button, updown, x, y);
+}
+
+void
+GLUTmotion (int x, int y)
+{
+  current_input.doMouseMotion(x, y);
+}
+
 // end of input.cxx