1
0
Fork 0

First steps towards configurable mouse input. Soon, this new code

(mainly in src/Input/input.cxx) will make src/GUI/mouse.cxx obsolete
and bring the mouse into the same input system as the joystick and
keyboard.  This is just preliminary work allowing, covering mouse
clicks (no motion yet), and it actually crashes on a middle or right
click.

The new mouse support is disabled by default until it become stable;
to try it out, you need to configure --with-new-mouse.
This commit is contained in:
david 2002-03-23 23:16:13 +00:00
parent d2156b5649
commit 9709dcb307
6 changed files with 368 additions and 106 deletions

View file

@ -66,6 +66,9 @@
/* Define to avoid Christian's new weather code */ /* Define to avoid Christian's new weather code */
#undef FG_NEW_ENVIRONMENT #undef FG_NEW_ENVIRONMENT
/* Define to use new experimental mouse input code */
#undef FG_NEW_MOUSE
/* Define if we are building FGFS (should always be defined) */ /* Define if we are building FGFS (should always be defined) */
#undef FGFS #undef FGFS

View file

@ -582,7 +582,7 @@ FGPanel::doMouseAction (int button, int updown, int x, int y)
if (updown == 1) { if (updown == 1) {
_mouseDown = false; _mouseDown = false;
_mouseInstrument = 0; _mouseInstrument = 0;
return true; return false;
} }
// Scale for the real window size. // Scale for the real window size.
@ -613,8 +613,7 @@ FGPanel::doMouseAction (int button, int updown, int x, int y)
_mouseX = x - ix; _mouseX = x - ix;
_mouseY = y - iy; _mouseY = y - iy;
// Always do the action once. // Always do the action once.
_mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY); return _mouseInstrument->doMouseAction(_mouseButton, _mouseX, _mouseY);
return true;
} }
} }
return false; return false;

View file

@ -111,7 +111,7 @@ FGBinding::read (const SGPropertyNode * node)
_command_name = node->getStringValue("command", ""); _command_name = node->getStringValue("command", "");
if (_command_name.empty()) { if (_command_name.empty()) {
SG_LOG(SG_INPUT, SG_ALERT, "No command supplied for binding."); SG_LOG(SG_INPUT, SG_WARN, "No command supplied for binding.");
_command = 0; _command = 0;
return; return;
} }
@ -134,7 +134,7 @@ FGBinding::fire () const
{ {
if (test()) { if (test()) {
if (_command == 0) { 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)) { } else if (!(*_command)(_arg, &_command_state)) {
SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command "
<< _command_name); << _command_name);
@ -142,6 +142,18 @@ FGBinding::fire () const
} }
} }
void
FGBinding::fire (int x, int y) const
{
if (test()) {
if (x >= 0)
_arg->setIntValue("x-pos", x);
if (y >= 0)
_arg->setIntValue("y-pos", y);
fire();
}
}
void void
FGBinding::fire (double setting) const FGBinding::fire (double setting) const
{ {
@ -168,6 +180,7 @@ FGInput current_input;
FGInput::FGInput () FGInput::FGInput ()
: _mouse_mode(0)
{ {
// no op // no op
} }
@ -182,6 +195,7 @@ FGInput::init ()
{ {
_init_keyboard(); _init_keyboard();
_init_joystick(); _init_joystick();
_init_mouse();
} }
void void
@ -201,17 +215,18 @@ FGInput::update (int dt)
{ {
_update_keyboard(); _update_keyboard();
_update_joystick(); _update_joystick();
_update_mouse();
} }
void void
FGInput::doKey (int k, int modifiers, int x, int y) FGInput::doKey (int k, int modifiers, int x, int y)
{ {
// SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
// << " with modifiers " << modifiers ); << " with modifiers " << modifiers );
// Sanity check. // Sanity check.
if (k < 0 || k >= MAX_KEYS) { 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; return;
} }
@ -219,8 +234,8 @@ FGInput::doKey (int k, int modifiers, int x, int y)
// Key pressed. // Key pressed.
if (modifiers&FG_MOD_UP == 0) { if (modifiers&FG_MOD_UP == 0) {
// SG_LOG( SG_INPUT, SG_INFO, "User pressed key " << k SG_LOG( SG_INPUT, SG_DEBUG, "User pressed key " << k
// << " with modifiers " << modifiers ); << " with modifiers " << modifiers );
if (!b.last_state || b.is_repeatable) { if (!b.last_state || b.is_repeatable) {
const binding_list_t &bindings = const binding_list_t &bindings =
_find_key_bindings(k, modifiers); _find_key_bindings(k, modifiers);
@ -235,8 +250,8 @@ FGInput::doKey (int k, int modifiers, int x, int y)
// Key released. // Key released.
else { else {
// SG_LOG(SG_INPUT, SG_INFO, "User released key " << k SG_LOG(SG_INPUT, SG_DEBUG, "User released key " << k
// << " with modifiers " << modifiers); << " with modifiers " << modifiers);
if (b.last_state) { if (b.last_state) {
const binding_list_t &bindings = const binding_list_t &bindings =
_find_key_bindings(k, modifiers); _find_key_bindings(k, modifiers);
@ -251,7 +266,7 @@ FGInput::doKey (int k, int modifiers, int x, int y)
// Use the old, default actions. // 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) if (modifiers&FG_MOD_UP)
return; return;
@ -330,22 +345,36 @@ FGInput::doKey (int k, int modifiers, int x, int y)
} }
} }
void
FGInput::doMouseClick (int b, int updown, int x, int y)
{
std::cout << "Mouse click " << b << ',' << updown << std::endl;
int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
_update_button(_mouse_bindings[0].buttons[b], modifiers, updown, x, y);
}
void
FGInput::doMouseMotion (int x, int y)
{
// TODO
}
void void
FGInput::_init_keyboard () FGInput::_init_keyboard ()
{ {
// TODO: zero the old bindings first. // 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"); SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
if (key_nodes == 0) { if (key_nodes == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "No key bindings (/input/keyboard)!!"); SG_LOG(SG_INPUT, SG_WARN, "No key bindings (/input/keyboard)!!");
return; key_nodes = fgGetNode("/input/keyboard", true);
} }
vector<SGPropertyNode *> keys = key_nodes->getChildren("key"); vector<SGPropertyNode *> keys = key_nodes->getChildren("key");
for (unsigned int i = 0; i < keys.size(); i++) { for (unsigned int i = 0; i < keys.size(); i++) {
int index = keys[i]->getIndex(); 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"); _key_bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
_read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE); _read_bindings(keys[i], _key_bindings[index].bindings, FG_MOD_NONE);
} }
@ -356,45 +385,45 @@ void
FGInput::_init_joystick () FGInput::_init_joystick ()
{ {
// TODO: zero the old bindings first. // 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"); SGPropertyNode * js_nodes = fgGetNode("/input/joysticks");
if (js_nodes == 0) { if (js_nodes == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "No joystick bindings (/input/joysticks)!!"); SG_LOG(SG_INPUT, SG_WARN, "No joystick bindings (/input/joysticks)!!");
return; js_nodes = fgGetNode("/input/joysticks", true);
} }
for (int i = 0; i < MAX_JOYSTICKS; i++) { for (int i = 0; i < MAX_JOYSTICKS; i++) {
const SGPropertyNode * js_node = js_nodes->getChild("js", i); SGPropertyNode * js_node = js_nodes->getChild("js", i);
if (js_node == 0) { if (js_node == 0) {
SG_LOG(SG_INPUT, SG_ALERT, "No bindings for joystick " << i); SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for joystick " << i);
continue; js_node = js_nodes->getChild("js", i, true);
} }
jsJoystick * js = new jsJoystick(i); jsJoystick * js = new jsJoystick(i);
_joystick_bindings[i].js = js; _joystick_bindings[i].js = js;
if (js->notWorking()) { if (js->notWorking()) {
SG_LOG(SG_INPUT, SG_INFO, "Joystick " << i << " not found"); SG_LOG(SG_INPUT, SG_WARN, "Joystick " << i << " not found");
continue; continue;
} }
#ifdef WIN32 #ifdef WIN32
JOYCAPS jsCaps ; JOYCAPS jsCaps ;
joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) ); joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
int nbuttons = jsCaps.wNumButtons; int nbuttons = jsCaps.wNumButtons;
if (nbuttons > MAX_BUTTONS) nbuttons = MAX_BUTTONS; if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
#else #else
int nbuttons = MAX_BUTTONS; int nbuttons = MAX_JOYSTICK_BUTTONS;
#endif #endif
int naxes = js->getNumAxes(); 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].naxes = naxes;
_joystick_bindings[i].nbuttons = nbuttons; _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 // Set up range arrays
float minRange[MAX_AXES]; float minRange[MAX_JOYSTICK_AXES];
float maxRange[MAX_AXES]; float maxRange[MAX_JOYSTICK_AXES];
float center[MAX_AXES]; float center[MAX_JOYSTICK_AXES];
// Initialize with default values // Initialize with default values
js->getMinRange(minRange); js->getMinRange(minRange);
@ -413,8 +442,8 @@ FGInput::_init_joystick ()
for (j = 0; j < naxes; j++) { for (j = 0; j < naxes; j++) {
const SGPropertyNode * axis_node = js_node->getChild("axis", j); const SGPropertyNode * axis_node = js_node->getChild("axis", j);
if (axis_node == 0) { if (axis_node == 0) {
SG_LOG(SG_INPUT, SG_INFO, "No bindings for axis " << j); SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for axis " << j);
continue; axis_node = js_node->getChild("axis", j, true);
} }
axis &a = _joystick_bindings[i].axes[j]; axis &a = _joystick_bindings[i].axes[j];
@ -442,7 +471,7 @@ FGInput::_init_joystick ()
char buf[8]; char buf[8];
for (j = 0; j < nbuttons; j++) { for (j = 0; j < nbuttons; j++) {
sprintf(buf, "%d", 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), _init_button(js_node->getChild("button", j),
_joystick_bindings[i].buttons[j], _joystick_bindings[i].buttons[j],
buf); buf);
@ -456,14 +485,44 @@ FGInput::_init_joystick ()
} }
inline void 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);
}
for (int i = 0; i < MAX_MICE; i++) {
const SGPropertyNode * mouse_node = mouse_nodes->getChild("mouse", i);
_mouse_bindings[i].buttons = new button[MAX_MOUSE_BUTTONS];
if (mouse_node == 0) {
SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for mouse " << i);
mouse_node = mouse_nodes->getChild("mouse", i, true);
}
char buf[8];
for (int j = 0; j < MAX_MOUSE_BUTTONS; j++) {
sprintf(buf, "%d", j);
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse button " << j);
_init_button(mouse_node->getChild("button", j),
_mouse_bindings[i].buttons[j],
buf);
}
}
}
void
FGInput::_init_button (const SGPropertyNode * node, FGInput::_init_button (const SGPropertyNode * node,
button &b, button &b,
const string name) const string name)
{ {
if (node == 0) if (node == 0) {
SG_LOG(SG_INPUT, SG_INFO, "No bindings for button " << name); SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for button " << name);
else { } else {
b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable); b.is_repeatable = node->getBoolValue("repeatable", b.is_repeatable);
// Get the bindings for the button // Get the bindings for the button
@ -485,7 +544,7 @@ FGInput::_update_joystick ()
int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones? int modifiers = FG_MOD_NONE; // FIXME: any way to get the real ones?
int buttons; int buttons;
// float js_val, diff; // float js_val, diff;
float axis_values[MAX_AXES]; float axis_values[MAX_JOYSTICK_AXES];
int i; int i;
int j; int j;
@ -507,10 +566,10 @@ FGInput::_update_joystick ()
// is unchanged; only a change in // is unchanged; only a change in
// position fires the bindings. // position fires the bindings.
if (fabs(axis_values[j] - a.last_value) > a.tolerance) { 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; SGPropertyNode node;
a.last_value = axis_values[j]; 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"); // << a.bindings[modifiers].size() << " bindings");
for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++) for (unsigned int k = 0; k < a.bindings[modifiers].size(); k++)
a.bindings[modifiers][k]->fire(axis_values[j]); a.bindings[modifiers][k]->fire(axis_values[j]);
@ -520,40 +579,49 @@ FGInput::_update_joystick ()
if (a.low.bindings[modifiers].size()) if (a.low.bindings[modifiers].size())
_update_button(_joystick_bindings[i].axes[j].low, _update_button(_joystick_bindings[i].axes[j].low,
modifiers, modifiers,
axis_values[j] < a.low_threshold); axis_values[j] < a.low_threshold,
-1, -1);
if (a.high.bindings[modifiers].size()) if (a.high.bindings[modifiers].size())
_update_button(_joystick_bindings[i].axes[j].high, _update_button(_joystick_bindings[i].axes[j].high,
modifiers, modifiers,
axis_values[j] > a.high_threshold); axis_values[j] > a.high_threshold,
-1, -1);
} }
// Fire bindings for the buttons. // Fire bindings for the buttons.
for (j = 0; j < _joystick_bindings[i].nbuttons; j++) { for (j = 0; j < _joystick_bindings[i].nbuttons; j++) {
_update_button(_joystick_bindings[i].buttons[j], _update_button(_joystick_bindings[i].buttons[j],
modifiers, modifiers,
(buttons & (1 << j)) > 0); (buttons & (1 << j)) > 0,
-1, -1);
} }
} }
} }
void
FGInput::_update_mouse ()
{
// no-op
}
void 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) { if (pressed) {
// The press event may be repeated. // The press event may be repeated.
if (!b.last_state || b.is_repeatable) { 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++) for (unsigned int k = 0; k < b.bindings[modifiers].size(); k++)
b.bindings[modifiers][k]->fire(); b.bindings[modifiers][k]->fire(x, y);
} }
} else { } else {
// The release event is never repeated. // The release event is never repeated.
if (b.last_state) { 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++) 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 +634,10 @@ FGInput::_read_bindings (const SGPropertyNode * node,
binding_list_t * binding_list, binding_list_t * binding_list,
int modifiers) int modifiers)
{ {
SG_LOG(SG_INPUT, SG_INFO, "Reading all bindings"); SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
vector<const SGPropertyNode *> bindings = node->getChildren("binding"); vector<const SGPropertyNode *> bindings = node->getChildren("binding");
for (unsigned int i = 0; i < bindings.size(); i++) { 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")); << bindings[i]->getStringValue("command"));
binding_list[modifiers].push_back(new FGBinding(bindings[i])); binding_list[modifiers].push_back(new FGBinding(bindings[i]));
} }
@ -678,8 +746,23 @@ FGInput::joystick::joystick ()
FGInput::joystick::~joystick () FGInput::joystick::~joystick ()
{ {
// delete js; // delete js;
// delete[] axes; delete[] axes;
// delete[] buttons; delete[] buttons;
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGInput::mouse
////////////////////////////////////////////////////////////////////////
FGInput::mouse::mouse ()
{
}
FGInput::mouse::~mouse ()
{
delete [] buttons;
} }
@ -708,68 +791,51 @@ static inline int get_mods ()
} }
/**
* Key-down event handler for Glut. ////////////////////////////////////////////////////////////////////////
* // GLUT C callbacks.
* <p>Pass the value on to the FGInput module unless PUI wants it.</p> ////////////////////////////////////////////////////////////////////////
*
* @param k The integer value for the key pressed. void
* @param x (unused) GLUTkey(unsigned char k, int x, int y)
* @param y (unused)
*/
void GLUTkey(unsigned char k, int x, int y)
{ {
// Give PUI a chance to grab it first. // Give PUI a chance to grab it first.
if (!puKeyboard(k, PU_DOWN)) if (!puKeyboard(k, PU_DOWN))
current_input.doKey(k, get_mods(), x, y); current_input.doKey(k, get_mods(), x, y);
} }
void
/** GLUTkeyup(unsigned char k, int x, int 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)
{ {
current_input.doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y); current_input.doKey(k, get_mods()|FGInput::FG_MOD_UP, x, y);
} }
void
/** GLUTspecialkey(int k, int x, int 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)
{ {
// Give PUI a chance to grab it first. // Give PUI a chance to grab it first.
if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN)) if (!puKeyboard(k + PU_KEY_GLUT_SPECIAL_OFFSET, PU_DOWN))
current_input.doKey(k + 256, get_mods(), x, y); current_input.doKey(k + 256, get_mods(), x, y);
} }
void
/** GLUTspecialkeyup(int k, int x, int 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)
{ {
current_input.doKey(k + 256, get_mods()|FGInput::FG_MOD_UP, x, 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 == GLUT_DOWN, x, y);
}
void
GLUTmotion (int x, int y)
{
puMouse(x, y);
// glutPostRedisplay();
current_input.doMouseMotion(x, y);
}
// end of input.cxx // end of input.cxx

View file

@ -122,6 +122,12 @@ public:
virtual void fire () const; virtual void fire () const;
/**
* Fire a binding with x and y positions.
*/
virtual void fire (int x, int y) const;
/** /**
* Fire a binding with a setting (i.e. joystick axis). * Fire a binding with a setting (i.e. joystick axis).
* *
@ -205,6 +211,26 @@ public:
virtual void doKey (int k, int modifiers, int x, int y); virtual void doKey (int k, int modifiers, int x, int y);
/**
* Handle a mouse click event.
*
* @param button The mouse button selected.
* @param updown Button status.
* @param x The X position of the mouse event, in screen coordinates.
* @param y The Y position of the mouse event, in screen coordinates.
*/
virtual void doMouseClick (int button, int updown, int x, int y);
/**
* Handle mouse motion.
*
* @param x The new mouse x position, in screen coordinates.
* @param y The new mouse y position, in screen coordinates.
*/
virtual void doMouseMotion (int x, int y);
private: private:
// Constants // Constants
enum enum
@ -216,8 +242,11 @@ private:
#else #else
MAX_JOYSTICKS = 10, MAX_JOYSTICKS = 10,
#endif #endif
MAX_AXES = _JS_MAX_AXES, MAX_JOYSTICK_AXES = _JS_MAX_AXES,
MAX_BUTTONS = 32 MAX_JOYSTICK_BUTTONS = 32,
MAX_MICE = 1,
MAX_MOUSE_BUTTONS
}; };
@ -266,6 +295,16 @@ private:
}; };
/**
* Settings for a mouse.
*/
struct mouse {
mouse ();
virtual ~mouse ();
button * buttons;
};
/** /**
* Initialize key bindings. * Initialize key bindings.
*/ */
@ -278,6 +317,12 @@ private:
void _init_joystick (); void _init_joystick ();
/**
* Initialize mouse bindings.
*/
void _init_mouse ();
/** /**
* Initialize a single button. * Initialize a single button.
*/ */
@ -298,10 +343,17 @@ private:
void _update_joystick (); void _update_joystick ();
/**
* Update the mouse.
*/
void _update_mouse ();
/** /**
* Update a single button. * Update a single button.
*/ */
inline void _update_button (button &b, int modifiers, bool pressed); inline void _update_button (button &b, int modifiers, bool pressed,
int x, int y);
/** /**
@ -319,6 +371,9 @@ private:
button _key_bindings[MAX_KEYS]; button _key_bindings[MAX_KEYS];
joystick _joystick_bindings[MAX_JOYSTICKS]; joystick _joystick_bindings[MAX_JOYSTICKS];
mouse _mouse_bindings[MAX_MICE];
int _mouse_mode;
}; };
@ -331,10 +386,77 @@ extern FGInput current_input;
// GLUT callbacks. // GLUT callbacks.
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Handle keyboard events // Handle GLUT events.
void GLUTkey(unsigned char k, int x, int y); extern "C" {
void GLUTkeyup(unsigned char k, int x, int y);
void GLUTspecialkey(int k, int x, int y);
void GLUTspecialkeyup(int k, int x, int y);
#endif // _CONTROLS_HXX /**
* 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);
/**
* 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);
/**
* 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);
/**
* 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);
/**
* Mouse click handler for Glut.
*
* @param button The mouse button pressed.
* @param updown Press or release flag.
* @param x The x-location of the click.
* @param y The y-location of the click.
*/
void GLUTmouse (int button, int updown, int x, int y);
/**
* Mouse motion handler for Glut.
*
* @param x The new x-location of the mouse.
* @param y The new y-location of the mouse.
*/
void GLUTmotion (int x, int y);
} // extern "C"
#endif // _INPUT_HXX

View file

@ -184,6 +184,47 @@ do_save (const SGPropertyNode * arg, SGCommandState ** state)
} }
/**
* Built-in command: let PUI handle a mouse click.
*
* button: the mouse button number, zero-based.
* is-down: true if the button is down, false if it is up.
* x-pos: the x position of the mouse click.
* y-pos: the y position of the mouse click.
*/
static bool
do_pui_mouse_click (const SGPropertyNode * arg, SGCommandState ** state)
{
return puMouse(arg->getIntValue("button"),
arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
arg->getIntValue("x-pos"),
arg->getIntValue("y-pos"));
}
/**
* Built-in command: let PUI *or* the panel handle a mouse click.
*
* button: the mouse button number, zero-based.
* is-down: true if the button is down, false if it is up.
* x-pos: the x position of the mouse click.
* y-pos: the y position of the mouse click.
*/
static bool
do_pui_or_panel_mouse_click (const SGPropertyNode * arg,
SGCommandState ** state)
{
int button = arg->getIntValue("button");
bool is_down = arg->getBoolValue("is-down");
int x = arg->getIntValue("x-pos");
int y = arg->getIntValue("y-pos");
return (puMouse(button, is_down ? PU_DOWN : PU_UP, x, y) ||
(current_panel != 0 &&
current_panel->doMouseAction(button,
is_down ? PU_DOWN : PU_UP, x, y)));
}
/** /**
* Built-in command: (re)load the panel. * Built-in command: (re)load the panel.
* *
@ -213,6 +254,28 @@ do_panel_load (const SGPropertyNode * arg, SGCommandState ** state)
} }
/**
* Built-in command: pass a mouse click to the panel.
*
* button: the mouse button number, zero-based.
* is-down: true if the button is down, false if it is up.
* x-pos: the x position of the mouse click.
* y-pos: the y position of the mouse click.
*/
static bool
do_panel_mouse_click (const SGPropertyNode * arg, SGCommandState ** state)
{
if (current_panel != 0)
return current_panel
->doMouseAction(arg->getIntValue("button"),
arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
arg->getIntValue("x-pos"),
arg->getIntValue("y-pos"));
else
return false;
}
/** /**
* Built-in command: (re)load preferences. * Built-in command: (re)load preferences.
* *
@ -574,7 +637,10 @@ static struct {
{ "exit", do_exit }, { "exit", do_exit },
{ "load", do_load }, { "load", do_load },
{ "save", do_save }, { "save", do_save },
{ "pui-mouse-click", do_pui_mouse_click },
{ "pui-or-panel-mouse-click", do_pui_or_panel_mouse_click },
{ "panel-load", do_panel_load }, { "panel-load", do_panel_load },
{ "panel-mouse-click", do_panel_mouse_click },
{ "preferences-load", do_preferences_load }, { "preferences-load", do_preferences_load },
{ "view-cycle", do_view_cycle }, { "view-cycle", do_view_cycle },
{ "screen-capture", do_screen_capture }, { "screen-capture", do_screen_capture },

View file

@ -1265,10 +1265,16 @@ int fgGlutInitEvents( void ) {
glutSpecialFunc(GLUTspecialkey); glutSpecialFunc(GLUTspecialkey);
glutSpecialUpFunc(GLUTspecialkeyup); glutSpecialUpFunc(GLUTspecialkeyup);
#if FG_NEW_MOUSE
glutMouseFunc (GLUTmouse);
glutMotionFunc (GLUTmotion);
glutPassiveMotionFunc (GLUTmotion);
#else
// call guiMouseFunc() whenever our little rodent is used // call guiMouseFunc() whenever our little rodent is used
glutMouseFunc ( guiMouseFunc ); glutMouseFunc ( guiMouseFunc );
glutMotionFunc (guiMotionFunc ); glutMotionFunc (guiMotionFunc );
glutPassiveMotionFunc (guiMotionFunc ); glutPassiveMotionFunc (guiMotionFunc );
#endif
// call fgMainLoop() whenever there is // call fgMainLoop() whenever there is
// nothing else to do // nothing else to do