Advanced input subsystem - Step2: Split up current input subsystem
- encapsulate code into classes - create separate subsystem for keyboard, mouse and joystick - group new subsystems into subsystemgroup "input"
This commit is contained in:
parent
aac4bec5c7
commit
aea9c750f3
17 changed files with 1972 additions and 1421 deletions
75
src/Input/FGButton.cxx
Normal file
75
src/Input/FGButton.cxx
Normal file
|
@ -0,0 +1,75 @@
|
|||
// FGButton.cxx -- a simple button/key wrapper class
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGButton.hxx"
|
||||
|
||||
FGButton::FGButton ()
|
||||
: is_repeatable(false),
|
||||
interval_sec(0),
|
||||
last_dt(0),
|
||||
last_state(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGButton::~FGButton ()
|
||||
{
|
||||
// bindings is a list of SGSharedPtr<SGBindings>
|
||||
// no cleanup required
|
||||
}
|
||||
|
||||
|
||||
void FGButton::init( const SGPropertyNode * node, const string name, string & module )
|
||||
{
|
||||
if (node == 0) {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "No bindings for button " << name);
|
||||
} else {
|
||||
is_repeatable = node->getBoolValue("repeatable", is_repeatable);
|
||||
// Get the bindings for the button
|
||||
read_bindings( node, bindings, KEYMOD_NONE, module );
|
||||
}
|
||||
}
|
||||
|
||||
void FGButton::update( int modifiers, bool pressed, int x, int y)
|
||||
{
|
||||
if (pressed) {
|
||||
// The press event may be repeated.
|
||||
if (!last_state || is_repeatable) {
|
||||
SG_LOG( SG_INPUT, SG_DEBUG, "Button has been pressed" );
|
||||
for (unsigned int k = 0; k < bindings[modifiers].size(); k++) {
|
||||
bindings[modifiers][k]->fire(x, y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The release event is never repeated.
|
||||
if (last_state) {
|
||||
SG_LOG( SG_INPUT, SG_DEBUG, "Button has been released" );
|
||||
for (unsigned int k = 0; k < bindings[modifiers|KEYMOD_RELEASED].size(); k++)
|
||||
bindings[modifiers|KEYMOD_RELEASED][k]->fire(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
last_state = pressed;
|
||||
}
|
||||
|
||||
|
44
src/Input/FGButton.hxx
Normal file
44
src/Input/FGButton.hxx
Normal file
|
@ -0,0 +1,44 @@
|
|||
// FGButton.hxx -- a simple button/key wrapper class
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef FGBUTTON_H
|
||||
#define FGBUTTON_H
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include <Main/fg_os.hxx>
|
||||
|
||||
class FGButton : public FGCommonInput {
|
||||
public:
|
||||
FGButton();
|
||||
virtual ~FGButton();
|
||||
void init( const SGPropertyNode * node, const string name, string & module );
|
||||
void update( int modifiers, bool pressed, int x = -1, int y = -1);
|
||||
bool is_repeatable;
|
||||
float interval_sec;
|
||||
float last_dt;
|
||||
int last_state;
|
||||
binding_list_t bindings[KEYMOD_MAX];
|
||||
};
|
||||
|
||||
#endif
|
71
src/Input/FGCommonInput.cxx
Normal file
71
src/Input/FGCommonInput.cxx
Normal file
|
@ -0,0 +1,71 @@
|
|||
// FGCommonInput.cxx -- common functions for all Input subsystems
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include <Main/globals.hxx>
|
||||
#include <Main/fg_os.hxx>
|
||||
|
||||
void FGCommonInput::read_bindings (const SGPropertyNode * node, binding_list_t * binding_list, int modifiers, string & module )
|
||||
{
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
|
||||
vector<SGPropertyNode_ptr> bindings = node->getChildren("binding");
|
||||
string nasal = "nasal";
|
||||
for (unsigned int i = 0; i < bindings.size(); i++) {
|
||||
const char *cmd = bindings[i]->getStringValue("command");
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Reading binding " << cmd);
|
||||
if (nasal.compare(cmd) == 0 && !module.empty())
|
||||
bindings[i]->setStringValue("module", module.c_str());
|
||||
binding_list[modifiers].push_back(new SGBinding(bindings[i], globals->get_props()));
|
||||
}
|
||||
|
||||
// Read nested bindings for modifiers
|
||||
if (node->getChild("mod-up") != 0)
|
||||
read_bindings(node->getChild("mod-up"), binding_list,
|
||||
modifiers|KEYMOD_RELEASED, module);
|
||||
|
||||
if (node->getChild("mod-shift") != 0)
|
||||
read_bindings(node->getChild("mod-shift"), binding_list,
|
||||
modifiers|KEYMOD_SHIFT, module);
|
||||
|
||||
if (node->getChild("mod-ctrl") != 0)
|
||||
read_bindings(node->getChild("mod-ctrl"), binding_list,
|
||||
modifiers|KEYMOD_CTRL, module);
|
||||
|
||||
if (node->getChild("mod-alt") != 0)
|
||||
read_bindings(node->getChild("mod-alt"), binding_list,
|
||||
modifiers|KEYMOD_ALT, module);
|
||||
|
||||
if (node->getChild("mod-meta") != 0)
|
||||
read_bindings(node->getChild("mod-meta"), binding_list,
|
||||
modifiers|KEYMOD_META, module);
|
||||
|
||||
if (node->getChild("mod-super") != 0)
|
||||
read_bindings(node->getChild("mod-super"), binding_list,
|
||||
modifiers|KEYMOD_SUPER, module);
|
||||
|
||||
if (node->getChild("mod-hyper") != 0)
|
||||
read_bindings(node->getChild("mod-hyper"), binding_list,
|
||||
modifiers|KEYMOD_HYPER, module);
|
||||
}
|
||||
|
51
src/Input/FGCommonInput.hxx
Normal file
51
src/Input/FGCommonInput.hxx
Normal file
|
@ -0,0 +1,51 @@
|
|||
// FGCommonInput.hxx -- common functions for all Input subsystems
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef FGCOMMONINPUT_H
|
||||
#define FGCOMMONINPUT_H
|
||||
|
||||
#include <vector>
|
||||
#include <simgear/structure/SGBinding.hxx>
|
||||
|
||||
#if defined( UL_WIN32 )
|
||||
#define TGT_PLATFORM "windows"
|
||||
#elif defined ( UL_MAC_OSX )
|
||||
#define TGT_PLATFORM "mac"
|
||||
#else
|
||||
#define TGT_PLATFORM "unix"
|
||||
#endif
|
||||
|
||||
class FGCommonInput {
|
||||
public:
|
||||
typedef vector<SGSharedPtr<SGBinding> > binding_list_t;
|
||||
|
||||
/*
|
||||
read all "binding" nodes directly under the specified base node and fill the
|
||||
vector of SGBinding supplied in binding_list. Reads all the mod-xxx bindings and
|
||||
add the corresponding SGBindings.
|
||||
*/
|
||||
static void read_bindings (const SGPropertyNode * base, binding_list_t * binding_list, int modifiers, string & module );
|
||||
};
|
||||
|
||||
#endif
|
77
src/Input/FGDeviceConfigurationMap.cxx
Normal file
77
src/Input/FGDeviceConfigurationMap.cxx
Normal file
|
@ -0,0 +1,77 @@
|
|||
// FGDeviceConfigurationMap.cxx -- a map to access xml device configuration
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGDeviceConfigurationMap.hxx"
|
||||
#include <simgear/props/props_io.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
FGDeviceConfigurationMap::FGDeviceConfigurationMap( const char * relative_path, SGPropertyNode_ptr aBase, const char * aChildname ) :
|
||||
base(aBase),
|
||||
childname(aChildname)
|
||||
{
|
||||
SGPath path(globals->get_fg_root());
|
||||
path.append( relative_path );
|
||||
|
||||
int index = 1000;
|
||||
scan_dir( path, &index);
|
||||
|
||||
vector<SGPropertyNode_ptr> childNodes = base->getChildren(childname);
|
||||
for (int k = (int)childNodes.size() - 1; k >= 0; k--) {
|
||||
SGPropertyNode *n = childNodes[k];
|
||||
vector<SGPropertyNode_ptr> names = n->getChildren("name");
|
||||
if (names.size() ) // && (n->getChildren("axis").size() || n->getChildren("button").size()))
|
||||
for (unsigned int j = 0; j < names.size(); j++)
|
||||
(*this)[names[j]->getStringValue()] = n;
|
||||
}
|
||||
}
|
||||
|
||||
FGDeviceConfigurationMap::~FGDeviceConfigurationMap()
|
||||
{
|
||||
base->removeChildren( childname );
|
||||
}
|
||||
|
||||
void FGDeviceConfigurationMap::scan_dir( SGPath & path, int *index)
|
||||
{
|
||||
ulDir *dir = ulOpenDir(path.c_str());
|
||||
if (dir) {
|
||||
ulDirEnt* dent;
|
||||
while ((dent = ulReadDir(dir)) != 0) {
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
SGPath p(path.str());
|
||||
p.append(dent->d_name);
|
||||
scan_dir(p, index);
|
||||
}
|
||||
ulCloseDir(dir);
|
||||
|
||||
} else if (path.extension() == "xml") {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Reading joystick file " << path.str());
|
||||
SGPropertyNode_ptr n = base->getChild(childname, (*index)++, true);
|
||||
readProperties(path.str(), n);
|
||||
n->setStringValue("source", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
48
src/Input/FGDeviceConfigurationMap.hxx
Normal file
48
src/Input/FGDeviceConfigurationMap.hxx
Normal file
|
@ -0,0 +1,48 @@
|
|||
// FGDeviceConfigurationMap.hxx -- a map to access xml device configuration
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FGDEVICECONFIGURATIONMAP_HXX
|
||||
#define _FGDEVICECONFIGURATIONMAP_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <map>
|
||||
using std::map;
|
||||
|
||||
class FGDeviceConfigurationMap : public map<string,SGPropertyNode_ptr> {
|
||||
public:
|
||||
FGDeviceConfigurationMap ( const char * relative_path, SGPropertyNode_ptr base, const char * childname );
|
||||
virtual ~FGDeviceConfigurationMap();
|
||||
private:
|
||||
void scan_dir( SGPath & path, int *index);
|
||||
SGPropertyNode_ptr base;
|
||||
const char * childname;
|
||||
};
|
||||
|
||||
#endif
|
203
src/Input/FGEventInput.cxx
Normal file
203
src/Input/FGEventInput.cxx
Normal file
|
@ -0,0 +1,203 @@
|
|||
// FGEventInput.cxx -- handle event driven input devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started July 2009.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGEventInput.hxx"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <simgear/io/sg_file.hxx>
|
||||
#include <poll.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
static inline bool StartsWith( string & s, const char * cp )
|
||||
{
|
||||
return s.compare( 0, strlen(cp), cp ) == 0;
|
||||
}
|
||||
|
||||
FGInputEvent * FGInputEvent::NewObject( SGPropertyNode_ptr node )
|
||||
{
|
||||
string name = node->getStringValue( "name" );
|
||||
if( StartsWith( name, "button-" ) )
|
||||
return new FGButtonEvent( node );
|
||||
|
||||
if( StartsWith( name, "rel-" ) )
|
||||
return new FGAxisEvent( node );
|
||||
|
||||
if( StartsWith( name, "abs-" ) )
|
||||
return new FGAxisEvent( node );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FGInputEvent::FGInputEvent( SGPropertyNode_ptr node ) :
|
||||
lastDt(0.0)
|
||||
{
|
||||
name = node->getStringValue( "name" );
|
||||
desc = node->getStringValue( "desc" );
|
||||
intervalSec = node->getDoubleValue("interval-sec",0.0);
|
||||
string module = "event";
|
||||
read_bindings( node, bindings, KEYMOD_NONE, module );
|
||||
}
|
||||
|
||||
FGInputEvent::~FGInputEvent()
|
||||
{
|
||||
}
|
||||
|
||||
void FGInputEvent::fire( FGEventData & eventData )
|
||||
{
|
||||
lastDt += eventData.dt;
|
||||
if( lastDt >= intervalSec ) {
|
||||
|
||||
for( binding_list_t::iterator it = bindings[KEYMOD_NONE].begin(); it != bindings[KEYMOD_NONE].end(); it++ )
|
||||
(*it)->fire( eventData.value, 1.0 );
|
||||
|
||||
lastDt -= intervalSec;
|
||||
}
|
||||
}
|
||||
|
||||
FGAxisEvent::FGAxisEvent( SGPropertyNode_ptr node ) :
|
||||
FGInputEvent( node )
|
||||
{
|
||||
tolerance = node->getDoubleValue("tolerance", 0.002);
|
||||
minRange = node->getDoubleValue("min-range", -1024.0);
|
||||
maxRange = node->getDoubleValue("max-range", 1024.0);
|
||||
center = node->getDoubleValue("center", 0.0);
|
||||
deadband = node->getDoubleValue("dead-band", 0.0);
|
||||
lowThreshold = node->getDoubleValue("low-threshold", -0.9);
|
||||
highThreshold = node->getDoubleValue("high-threshold", 0.9);
|
||||
lastValue = 9999999;
|
||||
}
|
||||
|
||||
void FGAxisEvent::fire( FGEventData & eventData )
|
||||
{
|
||||
if (fabs( eventData.value - lastValue) < tolerance)
|
||||
return;
|
||||
lastValue = eventData.value;
|
||||
FGInputEvent::fire( eventData );
|
||||
}
|
||||
|
||||
FGButtonEvent::FGButtonEvent( SGPropertyNode_ptr node ) :
|
||||
FGInputEvent( node )
|
||||
{
|
||||
}
|
||||
|
||||
void FGButtonEvent::fire( FGEventData & eventData )
|
||||
{
|
||||
FGInputEvent::fire( eventData );
|
||||
}
|
||||
|
||||
FGInputDevice::~FGInputDevice()
|
||||
{
|
||||
}
|
||||
|
||||
void FGInputDevice::HandleEvent( FGEventData & eventData )
|
||||
{
|
||||
string eventName = TranslateEventName( eventData );
|
||||
cout << GetName() << " has event " << eventName << endl;
|
||||
if( handledEvents.count( eventName ) > 0 ) {
|
||||
handledEvents[ eventName ]->fire( eventData );
|
||||
}
|
||||
}
|
||||
|
||||
void FGInputDevice::SetName( string name )
|
||||
{
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
const char * FGEventInput::PROPERTY_ROOT = "/input/event";
|
||||
|
||||
FGEventInput::FGEventInput() :
|
||||
configMap( "Input/Event", fgGetNode( PROPERTY_ROOT, true ), "device-named" )
|
||||
{
|
||||
}
|
||||
|
||||
FGEventInput::~FGEventInput()
|
||||
{
|
||||
for( map<int,FGInputDevice*>::iterator it = input_devices.begin(); it != input_devices.end(); it++ )
|
||||
delete (*it).second;
|
||||
input_devices.clear();
|
||||
}
|
||||
|
||||
void FGEventInput::init( )
|
||||
{
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing event bindings");
|
||||
SGPropertyNode * base = fgGetNode("/input/event", true);
|
||||
|
||||
}
|
||||
|
||||
void FGEventInput::postinit ()
|
||||
{
|
||||
}
|
||||
|
||||
void FGEventInput::AddDevice( FGInputDevice * inputDevice )
|
||||
{
|
||||
SGPropertyNode_ptr baseNode = fgGetNode( PROPERTY_ROOT, true );
|
||||
SGPropertyNode_ptr deviceNode = NULL;
|
||||
|
||||
// look for configuration in the device map
|
||||
if( configMap.count( inputDevice->GetName() ) > 0 ) {
|
||||
// found - copy to /input/event/device[n]
|
||||
|
||||
// find a free index
|
||||
unsigned index;
|
||||
for( index = 0; index < 1000; index++ )
|
||||
if( (deviceNode = baseNode->getNode( "device", index, false ) ) == NULL )
|
||||
break;
|
||||
|
||||
if( index == 1000 ) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "To many event devices - ignoring " << inputDevice->GetName() );
|
||||
return;
|
||||
}
|
||||
|
||||
// create this node
|
||||
deviceNode = baseNode->getNode( "device", index, true );
|
||||
|
||||
// and copy the properties from the configuration tree
|
||||
copyProperties( configMap[ inputDevice->GetName() ], deviceNode );
|
||||
}
|
||||
|
||||
if( deviceNode == NULL ) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "No configuration found for device " << inputDevice->GetName() );
|
||||
return;
|
||||
}
|
||||
|
||||
vector<SGPropertyNode_ptr> eventNodes = deviceNode->getChildren( "event" );
|
||||
for( vector<SGPropertyNode_ptr>::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ ) {
|
||||
FGInputEvent * p = FGInputEvent::NewObject( *it );
|
||||
if( p == NULL ) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Unhandled event/name in " << inputDevice->GetName() );
|
||||
continue;
|
||||
}
|
||||
inputDevice->AddHandledEvent( p );
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// add nodes for the last event:
|
||||
// last-event/name [string]
|
||||
// last-event/value [double]
|
||||
|
||||
try {
|
||||
inputDevice->Open();
|
||||
input_devices[ deviceNode->getIndex() ] = inputDevice;
|
||||
}
|
||||
catch( ... ) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "can't open InputDevice " << inputDevice->GetName() );
|
||||
}
|
||||
}
|
171
src/Input/FGEventInput.hxx
Normal file
171
src/Input/FGEventInput.hxx
Normal file
|
@ -0,0 +1,171 @@
|
|||
// FGEventInput.hxx -- handle event driven input devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started July 2009
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef __FGEVENTINPUT_HXX
|
||||
#define __FGEVENTINPUT_HXX
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include "FGButton.hxx"
|
||||
#include "FGDeviceConfigurationMap.hxx"
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
/*
|
||||
* A base class for event data.
|
||||
*/
|
||||
struct FGEventData {
|
||||
FGEventData( double aValue, double aDt ) : value(aValue), dt(aDt) {}
|
||||
double value;
|
||||
double dt;
|
||||
};
|
||||
|
||||
/*
|
||||
* A wrapper class for a configured event.
|
||||
*
|
||||
* <event>
|
||||
* <desc>Change the view pitch</desc>
|
||||
* <name>rel-x-rotate</name>
|
||||
* <binding>
|
||||
* <command>property-adjust</command>
|
||||
* <property>sim/current-view/pitch-offset-deg</property>
|
||||
* <factor type="double">0.01</factor>
|
||||
* <min type="double">-90.0</min>
|
||||
* <max type="double">90.0</max>
|
||||
* <wrap type="bool">false</wrap>
|
||||
* </binding>
|
||||
* </event>
|
||||
*/
|
||||
class FGInputEvent : public SGReferenced,FGCommonInput {
|
||||
public:
|
||||
/*
|
||||
* Constructor for the class. The arg node shall point
|
||||
* to the property corresponding to the <event> node
|
||||
*/
|
||||
FGInputEvent( SGPropertyNode_ptr node );
|
||||
virtual ~FGInputEvent();
|
||||
|
||||
/*
|
||||
* dispatch the event value through all bindings
|
||||
*/
|
||||
virtual void fire( FGEventData & eventData );
|
||||
|
||||
/*
|
||||
* access for the name property
|
||||
*/
|
||||
string GetName() const { return name; }
|
||||
|
||||
/*
|
||||
* access for the description property
|
||||
*/
|
||||
string GetDescription() const { return desc; }
|
||||
|
||||
static FGInputEvent * NewObject( SGPropertyNode_ptr node );
|
||||
|
||||
protected:
|
||||
/* A more or less meaningfull description of the event */
|
||||
string desc;
|
||||
|
||||
/* One of the predefined names of the event */
|
||||
string name;
|
||||
|
||||
/* A list of SGBinding objects */
|
||||
binding_list_t bindings[KEYMOD_MAX];
|
||||
|
||||
double lastDt;
|
||||
double intervalSec;
|
||||
};
|
||||
|
||||
class FGButtonEvent : public FGInputEvent {
|
||||
public:
|
||||
FGButtonEvent( SGPropertyNode_ptr node );
|
||||
virtual void fire( FGEventData & eventData );
|
||||
};
|
||||
|
||||
class FGAxisEvent : public FGInputEvent {
|
||||
public:
|
||||
FGAxisEvent( SGPropertyNode_ptr node );
|
||||
protected:
|
||||
virtual void fire( FGEventData & eventData );
|
||||
double tolerance;
|
||||
double minRange;
|
||||
double maxRange;
|
||||
double center;
|
||||
double deadband;
|
||||
double lowThreshold;
|
||||
double highThreshold;
|
||||
double lastValue;
|
||||
};
|
||||
|
||||
typedef class SGSharedPtr<FGInputEvent> FGInputEvent_ptr;
|
||||
|
||||
/*
|
||||
* A abstract class implementing basic functionality of input devices for
|
||||
* all operating systems. This is the base class for the O/S-specific
|
||||
* implementation of input device handlers
|
||||
*/
|
||||
class FGInputDevice : public SGReferenced {
|
||||
public:
|
||||
FGInputDevice() {}
|
||||
FGInputDevice( string aName ) : name(aName) {}
|
||||
|
||||
virtual ~FGInputDevice();
|
||||
|
||||
virtual void Open() = 0;
|
||||
virtual void Close() = 0;
|
||||
virtual const char * TranslateEventName( FGEventData & eventData ) = 0;
|
||||
|
||||
|
||||
void SetName( string name );
|
||||
string & GetName() { return name; }
|
||||
|
||||
void HandleEvent( FGEventData & eventData );
|
||||
void AddHandledEvent( FGInputEvent_ptr handledEvent ) {
|
||||
if( handledEvents.count( handledEvent->GetName() ) == 0 )
|
||||
handledEvents[handledEvent->GetName()] = handledEvent;
|
||||
}
|
||||
|
||||
private:
|
||||
map<string,FGInputEvent_ptr> handledEvents;
|
||||
string name;
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<FGInputDevice> FGInputDevice_ptr;
|
||||
|
||||
|
||||
/*
|
||||
* The Subsystem for the event input device
|
||||
*/
|
||||
class FGEventInput : public SGSubsystem,FGCommonInput {
|
||||
public:
|
||||
FGEventInput();
|
||||
virtual ~FGEventInput();
|
||||
virtual void init();
|
||||
virtual void postinit();
|
||||
|
||||
protected:
|
||||
static const char * PROPERTY_ROOT;
|
||||
|
||||
void AddDevice( FGInputDevice * inputDevice );
|
||||
map<int,FGInputDevice*> input_devices;
|
||||
FGDeviceConfigurationMap configMap;
|
||||
};
|
||||
|
||||
#endif
|
306
src/Input/FGJoystickInput.cxx
Normal file
306
src/Input/FGJoystickInput.cxx
Normal file
|
@ -0,0 +1,306 @@
|
|||
// FGJoystickInput.cxx -- handle user input from joystick devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGJoystickInput.hxx"
|
||||
#include "FGDeviceConfigurationMap.hxx"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
|
||||
FGJoystickInput::axis::axis ()
|
||||
: last_value(9999999),
|
||||
tolerance(0.002),
|
||||
low_threshold(-0.9),
|
||||
high_threshold(0.9),
|
||||
interval_sec(0),
|
||||
last_dt(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGJoystickInput::axis::~axis ()
|
||||
{
|
||||
}
|
||||
|
||||
FGJoystickInput::joystick::joystick ()
|
||||
: jsnum(0),
|
||||
js(0),
|
||||
naxes(0),
|
||||
nbuttons(0),
|
||||
axes(0),
|
||||
buttons(0)
|
||||
{
|
||||
}
|
||||
|
||||
FGJoystickInput::joystick::~joystick ()
|
||||
{
|
||||
// delete js? why not?
|
||||
// delete js;
|
||||
delete[] axes;
|
||||
delete[] buttons;
|
||||
}
|
||||
|
||||
|
||||
FGJoystickInput::FGJoystickInput()
|
||||
{
|
||||
}
|
||||
|
||||
FGJoystickInput::~FGJoystickInput()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void FGJoystickInput::init()
|
||||
{
|
||||
jsInit();
|
||||
// TODO: zero the old bindings first.
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick bindings");
|
||||
SGPropertyNode * js_nodes = fgGetNode("/input/joysticks", true);
|
||||
|
||||
FGDeviceConfigurationMap configMap("Input/Joysticks", js_nodes, "js-named");
|
||||
|
||||
for (int i = 0; i < MAX_JOYSTICKS; i++) {
|
||||
jsJoystick * js = new jsJoystick(i);
|
||||
bindings[i].js = js;
|
||||
|
||||
if (js->notWorking()) {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Joystick " << i << " not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
const char * name = js->getName();
|
||||
SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
|
||||
|
||||
if (js_node) {
|
||||
SG_LOG(SG_INPUT, SG_INFO, "Using existing bindings for joystick " << i);
|
||||
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \"" << name << '"');
|
||||
SGPropertyNode_ptr named;
|
||||
|
||||
if ((named = configMap[name])) {
|
||||
string source = named->getStringValue("source", "user defined");
|
||||
SG_LOG(SG_INPUT, SG_INFO, "... found joystick: " << source);
|
||||
|
||||
} else if ((named = configMap["default"])) {
|
||||
string source = named->getStringValue("source", "user defined");
|
||||
SG_LOG(SG_INPUT, SG_INFO, "No config found for joystick \"" << name
|
||||
<< "\"\nUsing default: \"" << source << '"');
|
||||
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "No joystick configuration file with <name>" << name << "</name> entry found!");
|
||||
}
|
||||
|
||||
js_node = js_nodes->getChild("js", i, true);
|
||||
copyProperties(named, js_node);
|
||||
js_node->setStringValue("id", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGJoystickInput::postinit()
|
||||
{
|
||||
FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
|
||||
SGPropertyNode_ptr js_nodes = fgGetNode("/input/joysticks");
|
||||
|
||||
for (int i = 0; i < MAX_JOYSTICKS; i++) {
|
||||
SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
|
||||
jsJoystick *js = bindings[i].js;
|
||||
if (!js_node || js->notWorking())
|
||||
continue;
|
||||
|
||||
#ifdef WIN32
|
||||
JOYCAPS jsCaps ;
|
||||
joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
|
||||
unsigned int nbuttons = jsCaps.wNumButtons;
|
||||
if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
|
||||
#else
|
||||
unsigned int nbuttons = MAX_JOYSTICK_BUTTONS;
|
||||
#endif
|
||||
|
||||
int naxes = js->getNumAxes();
|
||||
if (naxes > MAX_JOYSTICK_AXES) naxes = MAX_JOYSTICK_AXES;
|
||||
bindings[i].naxes = naxes;
|
||||
bindings[i].nbuttons = nbuttons;
|
||||
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing joystick " << i);
|
||||
|
||||
// Set up range arrays
|
||||
float minRange[MAX_JOYSTICK_AXES];
|
||||
float maxRange[MAX_JOYSTICK_AXES];
|
||||
float center[MAX_JOYSTICK_AXES];
|
||||
|
||||
// Initialize with default values
|
||||
js->getMinRange(minRange);
|
||||
js->getMaxRange(maxRange);
|
||||
js->getCenter(center);
|
||||
|
||||
// Allocate axes and buttons
|
||||
bindings[i].axes = new axis[naxes];
|
||||
bindings[i].buttons = new FGButton[nbuttons];
|
||||
|
||||
//
|
||||
// Initialize nasal groups.
|
||||
//
|
||||
ostringstream str;
|
||||
str << "__js" << i;
|
||||
string module = str.str();
|
||||
nasalsys->createModule(module.c_str(), module.c_str(), "", 0);
|
||||
|
||||
vector<SGPropertyNode_ptr> nasal = js_node->getChildren("nasal");
|
||||
unsigned int j;
|
||||
for (j = 0; j < nasal.size(); j++) {
|
||||
nasal[j]->setStringValue("module", module.c_str());
|
||||
nasalsys->handleCommand(nasal[j]);
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the axes.
|
||||
//
|
||||
vector<SGPropertyNode_ptr> axes = js_node->getChildren("axis");
|
||||
size_t nb_axes = axes.size();
|
||||
for (j = 0; j < nb_axes; j++ ) {
|
||||
const SGPropertyNode * axis_node = axes[j];
|
||||
const SGPropertyNode * num_node = axis_node->getChild("number");
|
||||
int n_axis = axis_node->getIndex();
|
||||
if (num_node != 0) {
|
||||
n_axis = num_node->getIntValue(TGT_PLATFORM, -1);
|
||||
|
||||
// Silently ignore platforms that are not specified within the
|
||||
// <number></number> section
|
||||
if (n_axis < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n_axis >= naxes) {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Dropping bindings for axis " << n_axis);
|
||||
continue;
|
||||
}
|
||||
axis &a = bindings[i].axes[n_axis];
|
||||
|
||||
js->setDeadBand(n_axis, axis_node->getDoubleValue("dead-band", 0.0));
|
||||
|
||||
a.tolerance = axis_node->getDoubleValue("tolerance", 0.002);
|
||||
minRange[n_axis] = axis_node->getDoubleValue("min-range", minRange[n_axis]);
|
||||
maxRange[n_axis] = axis_node->getDoubleValue("max-range", maxRange[n_axis]);
|
||||
center[n_axis] = axis_node->getDoubleValue("center", center[n_axis]);
|
||||
|
||||
read_bindings(axis_node, a.bindings, KEYMOD_NONE, module );
|
||||
|
||||
// Initialize the virtual axis buttons.
|
||||
a.low.init(axis_node->getChild("low"), "low", module );
|
||||
a.low_threshold = axis_node->getDoubleValue("low-threshold", -0.9);
|
||||
|
||||
a.high.init(axis_node->getChild("high"), "high", module );
|
||||
a.high_threshold = axis_node->getDoubleValue("high-threshold", 0.9);
|
||||
a.interval_sec = axis_node->getDoubleValue("interval-sec",0.0);
|
||||
a.last_dt = 0.0;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the buttons.
|
||||
//
|
||||
vector<SGPropertyNode_ptr> buttons = js_node->getChildren("button");
|
||||
char buf[32];
|
||||
for (j = 0; j < buttons.size() && j < nbuttons; j++) {
|
||||
const SGPropertyNode * button_node = buttons[j];
|
||||
const SGPropertyNode * num_node = button_node->getChild("number");
|
||||
size_t n_but = button_node->getIndex();
|
||||
if (num_node != 0) {
|
||||
n_but = num_node->getIntValue(TGT_PLATFORM,n_but);
|
||||
}
|
||||
|
||||
if (n_but >= nbuttons) {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Dropping bindings for button " << n_but);
|
||||
continue;
|
||||
}
|
||||
|
||||
sprintf(buf, "%d", n_but);
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing button " << n_but);
|
||||
bindings[i].buttons[n_but].init(button_node, buf, module );
|
||||
|
||||
// get interval-sec property
|
||||
FGButton &b = bindings[i].buttons[n_but];
|
||||
if (button_node != 0) {
|
||||
b.interval_sec = button_node->getDoubleValue("interval-sec",0.0);
|
||||
b.last_dt = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
js->setMinRange(minRange);
|
||||
js->setMaxRange(maxRange);
|
||||
js->setCenter(center);
|
||||
}
|
||||
}
|
||||
|
||||
void FGJoystickInput::update( double dt )
|
||||
{
|
||||
float axis_values[MAX_JOYSTICK_AXES];
|
||||
int modifiers = fgGetKeyModifiers();
|
||||
int buttons;
|
||||
|
||||
for (int i = 0; i < MAX_JOYSTICKS; i++) {
|
||||
|
||||
jsJoystick * js = bindings[i].js;
|
||||
if (js == 0 || js->notWorking())
|
||||
continue;
|
||||
|
||||
js->read(&buttons, axis_values);
|
||||
|
||||
// Fire bindings for the axes.
|
||||
for (int j = 0; j < bindings[i].naxes; j++) {
|
||||
axis &a = bindings[i].axes[j];
|
||||
|
||||
// Do nothing if the axis position
|
||||
// is unchanged; only a change in
|
||||
// position fires the bindings.
|
||||
if (fabs(axis_values[j] - a.last_value) > a.tolerance) {
|
||||
a.last_value = axis_values[j];
|
||||
for (unsigned int k = 0; k < a.bindings[KEYMOD_NONE].size(); k++)
|
||||
a.bindings[KEYMOD_NONE][k]->fire(axis_values[j]);
|
||||
}
|
||||
|
||||
// do we have to emulate axis buttons?
|
||||
a.last_dt += dt;
|
||||
if(a.last_dt >= a.interval_sec) {
|
||||
if (a.low.bindings[modifiers].size())
|
||||
bindings[i].axes[j].low.update( modifiers, axis_values[j] < a.low_threshold );
|
||||
|
||||
if (a.high.bindings[modifiers].size())
|
||||
bindings[i].axes[j].high.update( modifiers, axis_values[j] > a.high_threshold );
|
||||
|
||||
a.last_dt -= a.interval_sec;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire bindings for the buttons.
|
||||
for (int j = 0; j < bindings[i].nbuttons; j++) {
|
||||
FGButton &b = bindings[i].buttons[j];
|
||||
b.last_dt += dt;
|
||||
if(b.last_dt >= b.interval_sec) {
|
||||
bindings[i].buttons[j].update( modifiers, (buttons & (1 << j)) > 0 );
|
||||
b.last_dt -= b.interval_sec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
88
src/Input/FGJoystickInput.hxx
Normal file
88
src/Input/FGJoystickInput.hxx
Normal file
|
@ -0,0 +1,88 @@
|
|||
// FGJoystickInput.hxx -- handle user input from joystick devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FGJOYSTICKINPUT_HXX
|
||||
#define _FGJOYSTICKINPUT_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include "FGButton.hxx"
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <plib/js.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The Joystick Input Class
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
class FGJoystickInput : public SGSubsystem,FGCommonInput {
|
||||
public:
|
||||
FGJoystickInput();
|
||||
virtual ~FGJoystickInput();
|
||||
|
||||
virtual void init();
|
||||
virtual void postinit();
|
||||
virtual void update( double dt );
|
||||
|
||||
static const int MAX_JOYSTICKS = 10;
|
||||
static const int MAX_JOYSTICK_AXES = _JS_MAX_AXES;
|
||||
static const int MAX_JOYSTICK_BUTTONS = 32;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Settings for a single joystick axis.
|
||||
*/
|
||||
struct axis {
|
||||
axis ();
|
||||
virtual ~axis ();
|
||||
float last_value;
|
||||
float tolerance;
|
||||
binding_list_t bindings[KEYMOD_MAX];
|
||||
float low_threshold;
|
||||
float high_threshold;
|
||||
FGButton low;
|
||||
FGButton high;
|
||||
float interval_sec;
|
||||
double last_dt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Settings for a joystick.
|
||||
*/
|
||||
struct joystick {
|
||||
joystick ();
|
||||
virtual ~joystick ();
|
||||
int jsnum;
|
||||
jsJoystick * js;
|
||||
int naxes;
|
||||
int nbuttons;
|
||||
axis * axes;
|
||||
FGButton * buttons;
|
||||
};
|
||||
joystick bindings[MAX_JOYSTICKS];
|
||||
|
||||
};
|
||||
|
||||
#endif
|
259
src/Input/FGKeyboardInput.cxx
Normal file
259
src/Input/FGKeyboardInput.cxx
Normal file
|
@ -0,0 +1,259 @@
|
|||
// FGKeyboardInput.cxx -- handle user input from keyboard devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGKeyboardInput.hxx"
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Scripting/NasalSys.hxx>
|
||||
#include <plib/pu.h>
|
||||
|
||||
static int getModifiers ()
|
||||
{
|
||||
return fgGetKeyModifiers() >> 1;
|
||||
}
|
||||
|
||||
static bool getModShift ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_SHIFT) != 0;
|
||||
}
|
||||
|
||||
static bool getModCtrl ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_CTRL) != 0;
|
||||
}
|
||||
|
||||
static bool getModAlt ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_ALT) != 0;
|
||||
}
|
||||
|
||||
static bool getModMeta ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_META) != 0;
|
||||
}
|
||||
|
||||
static bool getModSuper ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_SUPER) != 0;
|
||||
}
|
||||
|
||||
static bool getModHyper ()
|
||||
{
|
||||
return (fgGetKeyModifiers() & KEYMOD_HYPER) != 0;
|
||||
}
|
||||
|
||||
FGKeyboardInput * FGKeyboardInput::keyboardInput = NULL;
|
||||
|
||||
FGKeyboardInput::FGKeyboardInput() :
|
||||
_key_event(fgGetNode("/devices/status/keyboard/event", true))
|
||||
{
|
||||
if( keyboardInput == NULL )
|
||||
keyboardInput = this;
|
||||
}
|
||||
|
||||
FGKeyboardInput::~FGKeyboardInput()
|
||||
{
|
||||
if( keyboardInput == this )
|
||||
keyboardInput = NULL;
|
||||
}
|
||||
|
||||
|
||||
void FGKeyboardInput::init()
|
||||
{
|
||||
fgRegisterKeyHandler(keyHandler);
|
||||
}
|
||||
|
||||
void FGKeyboardInput::postinit()
|
||||
{
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing key bindings");
|
||||
string module = "__kbd";
|
||||
SGPropertyNode * key_nodes = fgGetNode("/input/keyboard");
|
||||
if (key_nodes == NULL) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "No key bindings (/input/keyboard)!!");
|
||||
key_nodes = fgGetNode("/input/keyboard", true);
|
||||
}
|
||||
|
||||
FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
|
||||
vector<SGPropertyNode_ptr> nasal = key_nodes->getChildren("nasal");
|
||||
for (unsigned int j = 0; j < nasal.size(); j++) {
|
||||
nasal[j]->setStringValue("module", module.c_str());
|
||||
nasalsys->handleCommand(nasal[j]);
|
||||
}
|
||||
|
||||
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_DEBUG, "Binding key " << index);
|
||||
if( index >= MAX_KEYS ) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Key binding " << index << " out of range");
|
||||
continue;
|
||||
}
|
||||
|
||||
bindings[index].bindings->clear();
|
||||
bindings[index].is_repeatable = keys[i]->getBoolValue("repeatable");
|
||||
bindings[index].last_state = 0;
|
||||
read_bindings(keys[i], bindings[index].bindings, KEYMOD_NONE, module );
|
||||
}
|
||||
}
|
||||
|
||||
void FGKeyboardInput::bind()
|
||||
{
|
||||
fgTie("/devices/status/keyboard", getModifiers);
|
||||
fgTie("/devices/status/keyboard/shift", getModShift);
|
||||
fgTie("/devices/status/keyboard/ctrl", getModCtrl);
|
||||
fgTie("/devices/status/keyboard/alt", getModAlt);
|
||||
fgTie("/devices/status/keyboard/meta", getModMeta);
|
||||
fgTie("/devices/status/keyboard/super", getModSuper);
|
||||
fgTie("/devices/status/keyboard/hyper", getModHyper);
|
||||
|
||||
_key_event->tie("key", SGRawValuePointer<int>(&_key_code));
|
||||
_key_event->tie("pressed", SGRawValuePointer<bool>(&_key_pressed));
|
||||
_key_event->tie("modifier", SGRawValuePointer<int>(&_key_modifiers));
|
||||
_key_event->tie("modifier/shift", SGRawValuePointer<bool>(&_key_shift));
|
||||
_key_event->tie("modifier/ctrl", SGRawValuePointer<bool>(&_key_ctrl));
|
||||
_key_event->tie("modifier/alt", SGRawValuePointer<bool>(&_key_alt));
|
||||
_key_event->tie("modifier/meta", SGRawValuePointer<bool>(&_key_meta));
|
||||
_key_event->tie("modifier/super", SGRawValuePointer<bool>(&_key_super));
|
||||
_key_event->tie("modifier/hyper", SGRawValuePointer<bool>(&_key_hyper));
|
||||
}
|
||||
|
||||
void FGKeyboardInput::unbind()
|
||||
{
|
||||
fgUntie("/devices/status/keyboard");
|
||||
fgUntie("/devices/status/keyboard/shift");
|
||||
fgUntie("/devices/status/keyboard/ctrl");
|
||||
fgUntie("/devices/status/keyboard/alt");
|
||||
fgUntie("/devices/status/keyboard/meta");
|
||||
fgUntie("/devices/status/keyboard/super");
|
||||
fgUntie("/devices/status/keyboard/hyper");
|
||||
|
||||
_key_event->untie("key");
|
||||
_key_event->untie("pressed");
|
||||
_key_event->untie("modifier");
|
||||
_key_event->untie("modifier/shift");
|
||||
_key_event->untie("modifier/ctrl");
|
||||
_key_event->untie("modifier/alt");
|
||||
_key_event->untie("modifier/meta");
|
||||
_key_event->untie("modifier/super");
|
||||
_key_event->untie("modifier/hyper");
|
||||
}
|
||||
|
||||
void FGKeyboardInput::update( double dt )
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
const FGCommonInput::binding_list_t & FGKeyboardInput::_find_key_bindings (unsigned int k, int modifiers)
|
||||
{
|
||||
unsigned char kc = (unsigned char)k;
|
||||
FGButton &b = bindings[k];
|
||||
|
||||
// Try it straight, first.
|
||||
if (b.bindings[modifiers].size() > 0)
|
||||
return b.bindings[modifiers];
|
||||
|
||||
// Alt-Gr is CTRL+ALT
|
||||
else if (modifiers&(KEYMOD_CTRL|KEYMOD_ALT))
|
||||
return _find_key_bindings(k, modifiers&~(KEYMOD_CTRL|KEYMOD_ALT));
|
||||
|
||||
// Try removing the control modifier
|
||||
// for control keys.
|
||||
else if ((modifiers&KEYMOD_CTRL) && iscntrl(kc))
|
||||
return _find_key_bindings(k, modifiers&~KEYMOD_CTRL);
|
||||
|
||||
// Try removing shift modifier
|
||||
// for upper case or any punctuation
|
||||
// (since different keyboards will
|
||||
// shift different punctuation types)
|
||||
else if ((modifiers&KEYMOD_SHIFT) && (isupper(kc) || ispunct(kc)))
|
||||
return _find_key_bindings(k, modifiers&~KEYMOD_SHIFT);
|
||||
|
||||
// Try removing alt modifier for
|
||||
// high-bit characters.
|
||||
else if ((modifiers&KEYMOD_ALT) && k >= 128 && k < 256)
|
||||
return _find_key_bindings(k, modifiers&~KEYMOD_ALT);
|
||||
|
||||
// Give up and return the empty vector.
|
||||
else
|
||||
return b.bindings[modifiers];
|
||||
}
|
||||
|
||||
void FGKeyboardInput::doKey (int k, int modifiers, int x, int y)
|
||||
{
|
||||
// Sanity check.
|
||||
if (k < 0 || k >= MAX_KEYS) {
|
||||
SG_LOG(SG_INPUT, SG_WARN, "Key value " << k << " out of range");
|
||||
return;
|
||||
}
|
||||
|
||||
_key_code = k;
|
||||
_key_modifiers = modifiers >> 1;
|
||||
_key_pressed = (modifiers & KEYMOD_RELEASED) == 0;
|
||||
_key_shift = getModShift();
|
||||
_key_ctrl = getModCtrl();
|
||||
_key_alt = getModAlt();
|
||||
_key_meta = getModMeta();
|
||||
_key_super = getModSuper();
|
||||
_key_hyper = getModHyper();
|
||||
_key_event->fireValueChanged();
|
||||
if (_key_code < 0)
|
||||
return;
|
||||
|
||||
k = _key_code;
|
||||
modifiers = _key_modifiers << 1;
|
||||
if (!_key_pressed)
|
||||
modifiers |= KEYMOD_RELEASED;
|
||||
FGButton &b = bindings[k];
|
||||
|
||||
// Key pressed.
|
||||
if (!(modifiers & KEYMOD_RELEASED)) {
|
||||
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);
|
||||
|
||||
for (unsigned int i = 0; i < bindings.size(); i++)
|
||||
bindings[i]->fire();
|
||||
b.last_state = 1;
|
||||
}
|
||||
}
|
||||
// Key released.
|
||||
else {
|
||||
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);
|
||||
for (unsigned int i = 0; i < bindings.size(); i++)
|
||||
bindings[i]->fire();
|
||||
b.last_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGKeyboardInput::keyHandler(int key, int keymod, int mousex, int mousey)
|
||||
{
|
||||
if((keymod & KEYMOD_RELEASED) == 0)
|
||||
if(puKeyboard(key, PU_DOWN))
|
||||
return;
|
||||
|
||||
if(keyboardInput)
|
||||
keyboardInput->doKey(key, keymod, mousex, mousey);
|
||||
}
|
71
src/Input/FGKeyboardInput.hxx
Normal file
71
src/Input/FGKeyboardInput.hxx
Normal file
|
@ -0,0 +1,71 @@
|
|||
// FGKeyboardInput.hxx -- handle user input from keyboard devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#ifndef _FGKEYBOARDINPUT_HXX
|
||||
#define _FGKEYBOARDINPUT_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include "FGButton.hxx"
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The Keyboard Input Class
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
class FGKeyboardInput : public SGSubsystem,FGCommonInput {
|
||||
public:
|
||||
FGKeyboardInput();
|
||||
virtual ~FGKeyboardInput();
|
||||
|
||||
virtual void init();
|
||||
virtual void postinit();
|
||||
virtual void bind();
|
||||
virtual void unbind();
|
||||
virtual void update( double dt );
|
||||
|
||||
static const int MAX_KEYS = 1024;
|
||||
|
||||
private:
|
||||
const binding_list_t& _find_key_bindings (unsigned int k, int modifiers);
|
||||
void doKey (int k, int modifiers, int x, int y);
|
||||
|
||||
static void keyHandler(int key, int keymod, int mousex, int mousey);
|
||||
static FGKeyboardInput * keyboardInput;
|
||||
FGButton bindings[MAX_KEYS];
|
||||
SGPropertyNode_ptr _key_event;
|
||||
int _key_code;
|
||||
int _key_modifiers;
|
||||
bool _key_pressed;
|
||||
bool _key_shift;
|
||||
bool _key_ctrl;
|
||||
bool _key_alt;
|
||||
bool _key_meta;
|
||||
bool _key_super;
|
||||
bool _key_hyper;
|
||||
};
|
||||
|
||||
#endif
|
363
src/Input/FGMouseInput.cxx
Normal file
363
src/Input/FGMouseInput.cxx
Normal file
|
@ -0,0 +1,363 @@
|
|||
// FGMouseInput.cxx -- handle user input from mouse devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include "FGMouseInput.hxx"
|
||||
|
||||
|
||||
void ActivePickCallbacks::init( int b, const osgGA::GUIEventAdapter* ea )
|
||||
{
|
||||
// Get the list of hit callbacks. Take the first callback that
|
||||
// accepts the mouse button press and ignore the rest of them
|
||||
// That is they get sorted by distance and by scenegraph depth.
|
||||
// The nearest one is the first one and the deepest
|
||||
// (the most specialized one in the scenegraph) is the first.
|
||||
std::vector<SGSceneryPick> pickList;
|
||||
if (FGRenderer::pick(pickList, ea)) {
|
||||
std::vector<SGSceneryPick>::const_iterator i;
|
||||
for (i = pickList.begin(); i != pickList.end(); ++i) {
|
||||
if (i->callback->buttonPressed(b, i->info)) {
|
||||
(*this)[b].push_back(i->callback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActivePickCallbacks::update( double dt )
|
||||
{
|
||||
// handle repeatable mouse press events
|
||||
for( iterator mi = begin(); mi != end(); ++mi ) {
|
||||
std::list<SGSharedPtr<SGPickCallback> >::iterator li;
|
||||
for (li = mi->second.begin(); li != mi->second.end(); ++li) {
|
||||
(*li)->update(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include <plib/pu.h>
|
||||
#include <Model/panelnode.hxx>
|
||||
#include <Cockpit/panel.hxx>
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The Mouse Input Implementation
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const FGMouseInput::MouseCursorMap FGMouseInput::mouse_cursor_map[] = {
|
||||
{ "none", MOUSE_CURSOR_NONE },
|
||||
{ "inherit", MOUSE_CURSOR_POINTER },
|
||||
{ "wait", MOUSE_CURSOR_WAIT },
|
||||
{ "crosshair", MOUSE_CURSOR_CROSSHAIR },
|
||||
{ "left-right", MOUSE_CURSOR_LEFTRIGHT },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
FGMouseInput * FGMouseInput::mouseInput = NULL;
|
||||
|
||||
FGMouseInput::FGMouseInput()
|
||||
{
|
||||
if( mouseInput == NULL )
|
||||
mouseInput = this;
|
||||
}
|
||||
|
||||
FGMouseInput::~FGMouseInput()
|
||||
{
|
||||
if( mouseInput == this )
|
||||
mouseInput = NULL;
|
||||
}
|
||||
|
||||
void FGMouseInput::init()
|
||||
{
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Initializing mouse bindings");
|
||||
string module = "";
|
||||
|
||||
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 = bindings[i];
|
||||
|
||||
// Grab node pointers
|
||||
char buf[64];
|
||||
sprintf(buf, "/devices/status/mice/mouse[%d]/mode", i);
|
||||
m.mode_node = fgGetNode(buf);
|
||||
if (m.mode_node == NULL) {
|
||||
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 = MOUSE_CURSOR_POINTER;
|
||||
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 FGButton[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);
|
||||
m.modes[j].buttons[k].init( mode_node->getChild("button", k), buf, module );
|
||||
}
|
||||
|
||||
// Read the axis bindings for this mode
|
||||
read_bindings(mode_node->getChild("x-axis", 0, true), m.modes[j].x_bindings, KEYMOD_NONE, module );
|
||||
read_bindings(mode_node->getChild("y-axis", 0, true), m.modes[j].y_bindings, KEYMOD_NONE, module );
|
||||
}
|
||||
}
|
||||
|
||||
fgRegisterMouseClickHandler(mouseClickHandler);
|
||||
fgRegisterMouseMotionHandler(mouseMotionHandler);
|
||||
}
|
||||
|
||||
void FGMouseInput::update ( double dt )
|
||||
{
|
||||
mouse &m = bindings[0];
|
||||
int mode = m.mode_node->getIntValue();
|
||||
if (mode != m.current_mode) {
|
||||
m.current_mode = mode;
|
||||
m.timeout = fgGetDouble( "/sim/mouse/cursor-timeout-sec", 10.0 );
|
||||
if (mode >= 0 && mode < m.nModes) {
|
||||
fgSetMouseCursor(m.modes[mode].cursor);
|
||||
m.x = fgGetInt("/sim/startup/xsize", 800) / 2;
|
||||
m.y = fgGetInt("/sim/startup/ysize", 600) / 2;
|
||||
fgWarpMouse(m.x, m.y);
|
||||
} else {
|
||||
SG_LOG(SG_INPUT, SG_DEBUG, "Mouse mode " << mode << " out of range");
|
||||
fgSetMouseCursor(MOUSE_CURSOR_POINTER);
|
||||
}
|
||||
}
|
||||
|
||||
if ( fgGetBool( "/sim/mouse/hide-cursor", true ) ) {
|
||||
if ( m.x != m.save_x || m.y != m.save_y ) {
|
||||
m.timeout = fgGetDouble( "/sim/mouse/cursor-timeout-sec", 10.0 );
|
||||
if (fgGetMouseCursor() == MOUSE_CURSOR_NONE)
|
||||
fgSetMouseCursor(m.modes[mode].cursor);
|
||||
} else {
|
||||
m.timeout -= dt;
|
||||
if ( m.timeout <= 0.0 ) {
|
||||
fgSetMouseCursor(MOUSE_CURSOR_NONE);
|
||||
m.timeout = 0.0;
|
||||
}
|
||||
}
|
||||
m.save_x = m.x;
|
||||
m.save_y = m.y;
|
||||
}
|
||||
|
||||
activePickCallbacks.update( dt );
|
||||
}
|
||||
|
||||
FGMouseInput::mouse::mouse ()
|
||||
: x(-1),
|
||||
y(-1),
|
||||
save_x(-1),
|
||||
save_y(-1),
|
||||
nModes(1),
|
||||
current_mode(0),
|
||||
modes(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FGMouseInput::mouse::~mouse ()
|
||||
{
|
||||
delete [] modes;
|
||||
}
|
||||
|
||||
FGMouseInput::mouse_mode::mouse_mode ()
|
||||
: cursor(MOUSE_CURSOR_POINTER),
|
||||
constrained(false),
|
||||
pass_through(false),
|
||||
buttons(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
FGMouseInput::mouse_mode::~mouse_mode ()
|
||||
{
|
||||
// FIXME: memory leak
|
||||
// for (int i = 0; i < KEYMOD_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;
|
||||
}
|
||||
|
||||
void FGMouseInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
|
||||
{
|
||||
int modifiers = fgGetKeyModifiers();
|
||||
|
||||
mouse &m = 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 == MOUSE_BUTTON_DOWN);
|
||||
|
||||
// Pass on to PUI and the panel if
|
||||
// requested, and return if one of
|
||||
// them consumes the event.
|
||||
|
||||
if (updown != MOUSE_BUTTON_DOWN) {
|
||||
// Execute the mouse up event in any case, may be we should
|
||||
// stop processing here?
|
||||
while (!activePickCallbacks[b].empty()) {
|
||||
activePickCallbacks[b].front()->buttonReleased();
|
||||
activePickCallbacks[b].pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
if (mode.pass_through) {
|
||||
if (0 <= x && 0 <= y && puMouse(b, updown, x, y))
|
||||
return;
|
||||
else if (0 <= x && 0 <= y && (globals->get_current_panel() != 0) &&
|
||||
globals->get_current_panel()->getVisibility() &&
|
||||
globals->get_current_panel()->doMouseAction(b, updown, x, y))
|
||||
return;
|
||||
else if (0 <= x && 0 <= y && fgHandle3DPanelMouseEvent(b, updown, x, y))
|
||||
return;
|
||||
else {
|
||||
// pui didn't want the click event so compute a
|
||||
// scenegraph intersection point corresponding to the mouse click
|
||||
if (updown == MOUSE_BUTTON_DOWN) {
|
||||
activePickCallbacks.init( b, ea );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
m.modes[m.current_mode].buttons[b].update( modifiers, 0 != updown, x, y);
|
||||
}
|
||||
|
||||
void FGMouseInput::doMouseMotion (int x, int y)
|
||||
{
|
||||
// Don't call fgGetKeyModifiers() here, until we are using a
|
||||
// toolkit that supports getting the mods from outside a key
|
||||
// callback. Glut doesn't.
|
||||
int modifiers = KEYMOD_NONE;
|
||||
|
||||
int xsize = fgGetInt("/sim/startup/xsize", 800);
|
||||
int ysize = fgGetInt("/sim/startup/ysize", 600);
|
||||
|
||||
mouse &m = bindings[0];
|
||||
|
||||
if (m.current_mode < 0 || m.current_mode >= m.nModes) {
|
||||
m.x = x;
|
||||
m.y = y;
|
||||
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)) {
|
||||
m.x = x;
|
||||
m.y = 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 <= (xsize * .25) || x >= (xsize * .75)) {
|
||||
x = int(xsize * .5);
|
||||
need_warp = true;
|
||||
}
|
||||
|
||||
if (y <= (ysize * .25) || y >= (ysize * .75)) {
|
||||
y = int(ysize * .5);
|
||||
need_warp = true;
|
||||
}
|
||||
|
||||
if (need_warp)
|
||||
fgWarpMouse(x, y);
|
||||
}
|
||||
|
||||
if (m.x != x)
|
||||
fgSetInt("/devices/status/mice/mouse/x", m.x = x);
|
||||
|
||||
if (m.y != y)
|
||||
fgSetInt("/devices/status/mice/mouse/y", m.y = y);
|
||||
}
|
||||
|
||||
void FGMouseInput::mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea)
|
||||
{
|
||||
if(mouseInput)
|
||||
mouseInput->doMouseClick(button, updown, x, y, mainWindow, ea);
|
||||
}
|
||||
|
||||
void FGMouseInput::mouseMotionHandler(int x, int y)
|
||||
{
|
||||
if (mouseInput != 0)
|
||||
mouseInput->doMouseMotion(x, y);
|
||||
}
|
||||
|
||||
|
123
src/Input/FGMouseInput.hxx
Normal file
123
src/Input/FGMouseInput.hxx
Normal file
|
@ -0,0 +1,123 @@
|
|||
// FGMouseInput.hxx -- handle user input from mouse devices
|
||||
//
|
||||
// Written by Torsten Dreyer, started August 2009
|
||||
// Based on work from David Megginson, started May 2001.
|
||||
//
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifndef _FGMOUSEINPUT_HXX
|
||||
#define _FGMOUSEINPUT_HXX
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include "FGCommonInput.hxx"
|
||||
#include "FGButton.hxx"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||
#include <Main/renderer.hxx>
|
||||
/**
|
||||
* List of currently pressed mouse button events
|
||||
*/
|
||||
class ActivePickCallbacks : public std::map<int, std::list<SGSharedPtr<SGPickCallback> > > {
|
||||
public:
|
||||
void update( double dt );
|
||||
void init( int b, const osgGA::GUIEventAdapter* ea );
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// The Mouse Input Class
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
class FGMouseInput : public SGSubsystem,FGCommonInput {
|
||||
public:
|
||||
FGMouseInput();
|
||||
virtual ~FGMouseInput();
|
||||
|
||||
virtual void init();
|
||||
virtual void update( double dt );
|
||||
|
||||
static const int MAX_MICE = 1;
|
||||
static const int MAX_MOUSE_BUTTONS = 8;
|
||||
|
||||
private:
|
||||
void doMouseClick (int b, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter* ea);
|
||||
void doMouseMotion (int x, int y);
|
||||
static FGMouseInput * mouseInput;
|
||||
static void mouseClickHandler(int button, int updown, int x, int y, bool mainWindow, const osgGA::GUIEventAdapter*);
|
||||
static void mouseMotionHandler(int x, int y);
|
||||
|
||||
ActivePickCallbacks activePickCallbacks;
|
||||
/**
|
||||
* Settings for a mouse mode.
|
||||
*/
|
||||
struct mouse_mode {
|
||||
mouse_mode ();
|
||||
virtual ~mouse_mode ();
|
||||
int cursor;
|
||||
bool constrained;
|
||||
bool pass_through;
|
||||
FGButton * buttons;
|
||||
binding_list_t x_bindings[KEYMOD_MAX];
|
||||
binding_list_t y_bindings[KEYMOD_MAX];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Settings for a mouse.
|
||||
*/
|
||||
struct mouse {
|
||||
mouse ();
|
||||
virtual ~mouse ();
|
||||
int x;
|
||||
int y;
|
||||
int save_x;
|
||||
int save_y;
|
||||
SGPropertyNode_ptr mode_node;
|
||||
SGPropertyNode_ptr mouse_button_nodes[MAX_MOUSE_BUTTONS];
|
||||
int nModes;
|
||||
int current_mode;
|
||||
double timeout;
|
||||
mouse_mode * modes;
|
||||
};
|
||||
|
||||
//
|
||||
// Map of all known cursor names
|
||||
// This used to contain all the Glut cursors, but those are
|
||||
// not defined by other toolkits. It now supports only the cursor
|
||||
// images we actually use, in the interest of portability. Someday,
|
||||
// it would be cool to write an OpenGL cursor renderer, with the
|
||||
// cursors defined as textures referenced in the property tree. This
|
||||
// list could then be eliminated. -Andy
|
||||
//
|
||||
const static struct MouseCursorMap {
|
||||
const char * name;
|
||||
int cursor;
|
||||
} mouse_cursor_map[];
|
||||
|
||||
mouse bindings[MAX_MICE];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -2,7 +2,12 @@ AM_CXXFLAGS = -DPKGLIBDIR=\"$(pkgdatadir)\"
|
|||
|
||||
noinst_LIBRARIES = libInput.a
|
||||
|
||||
libInput_a_SOURCES = input.cxx input.hxx
|
||||
libInput_a_SOURCES = input.cxx input.hxx FGCommonInput.cxx FGCommonInput.hxx \
|
||||
FGDeviceConfigurationMap.cxx FGDeviceConfigurationMap.hxx \
|
||||
FGButton.cxx FGButton.hxx \
|
||||
FGMouseInput.cxx FGMouseInput.hxx \
|
||||
FGKeyboardInput.cxx FGKeyboardInput.hxx \
|
||||
FGJoystickInput.cxx FGJoystickInput.hxx
|
||||
|
||||
bin_PROGRAMS = js_demo fgjs
|
||||
|
||||
|
|
1149
src/Input/input.cxx
1149
src/Input/input.cxx
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,10 @@
|
|||
// input.hxx -- handle user input from various sources.
|
||||
//
|
||||
// Written by David Megginson, started May 2001.
|
||||
// Major redesign by Torsten Dreyer, started August 2009
|
||||
//
|
||||
// Copyright (C) 2001 David Megginson, david@megginson.com
|
||||
// Copyright (C) 2009 Torsten Dreyer, Torsten (at) t3r _dot_ de
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
|
@ -28,40 +30,10 @@
|
|||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
#include <plib/js.h>
|
||||
#include <plib/ul.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
#include <simgear/structure/SGBinding.hxx>
|
||||
#include <simgear/props/condition.hxx>
|
||||
#include <simgear/props/props.hxx>
|
||||
#include <simgear/scene/util/SGSceneUserData.hxx>
|
||||
|
||||
#include <Main/fg_os.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include <Main/globals.hxx>
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined( UL_WIN32 )
|
||||
#define TGT_PLATFORM "windows"
|
||||
#elif defined ( UL_MAC_OSX )
|
||||
#define TGT_PLATFORM "mac"
|
||||
#else
|
||||
#define TGT_PLATFORM "unix"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -76,7 +48,7 @@ using std::vector;
|
|||
* keyboard, joystick, mouse, or even panel switches -- in a consistent
|
||||
* way, and to allow users to rebind any of the actions at runtime.</p>
|
||||
*/
|
||||
class FGInput : public SGSubsystem
|
||||
class FGInput : public SGSubsystemGroup
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
@ -89,259 +61,6 @@ public:
|
|||
*/
|
||||
virtual ~FGInput();
|
||||
|
||||
//
|
||||
// Implementation of SGSubsystem.
|
||||
//
|
||||
virtual void init ();
|
||||
virtual void reinit ();
|
||||
virtual void postinit ();
|
||||
virtual void bind ();
|
||||
virtual void unbind ();
|
||||
virtual void update (double dt);
|
||||
virtual void suspend ();
|
||||
virtual void resume ();
|
||||
virtual bool is_suspended () const;
|
||||
|
||||
|
||||
/**
|
||||
* Control whether this is the default module to receive events.
|
||||
*
|
||||
* The first input module created will set itself as the default
|
||||
* automatically.
|
||||
*
|
||||
* @param status true if this should be the default module for
|
||||
* events, false otherwise.
|
||||
*/
|
||||
virtual void makeDefault (bool status = true);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a single keystroke.
|
||||
*
|
||||
* @param k The integer key code, see Main/fg_os.hxx
|
||||
* @param modifiers Modifier keys pressed (bitfield).
|
||||
* @param x The mouse x position at the time of keypress.
|
||||
* @param y The mouse y position at the time of keypress.
|
||||
*/
|
||||
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, bool mainWindow, const osgGA::GUIEventAdapter*);
|
||||
|
||||
|
||||
/**
|
||||
* 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:
|
||||
// Constants
|
||||
enum
|
||||
{
|
||||
MAX_KEYS = 1024,
|
||||
MAX_JOYSTICKS = 10,
|
||||
MAX_JOYSTICK_AXES = _JS_MAX_AXES,
|
||||
MAX_JOYSTICK_BUTTONS = 32,
|
||||
|
||||
MAX_MICE = 1,
|
||||
MAX_MOUSE_BUTTONS = 8
|
||||
};
|
||||
struct mouse;
|
||||
friend struct mouse;
|
||||
|
||||
typedef vector<SGSharedPtr<SGBinding> > binding_list_t;
|
||||
|
||||
/**
|
||||
* Settings for a key or button.
|
||||
*/
|
||||
struct button {
|
||||
button ();
|
||||
virtual ~button ();
|
||||
bool is_repeatable;
|
||||
float interval_sec;
|
||||
float last_dt;
|
||||
int last_state;
|
||||
binding_list_t bindings[KEYMOD_MAX];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Settings for a single joystick axis.
|
||||
*/
|
||||
struct axis {
|
||||
axis ();
|
||||
virtual ~axis ();
|
||||
float last_value;
|
||||
float tolerance;
|
||||
binding_list_t bindings[KEYMOD_MAX];
|
||||
float low_threshold;
|
||||
float high_threshold;
|
||||
struct button low;
|
||||
struct button high;
|
||||
float interval_sec;
|
||||
double last_dt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Settings for a joystick.
|
||||
*/
|
||||
struct joystick {
|
||||
joystick ();
|
||||
virtual ~joystick ();
|
||||
int jsnum;
|
||||
jsJoystick * js;
|
||||
int naxes;
|
||||
int nbuttons;
|
||||
axis * axes;
|
||||
button * buttons;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Settings for a mouse mode.
|
||||
*/
|
||||
struct mouse_mode {
|
||||
mouse_mode ();
|
||||
virtual ~mouse_mode ();
|
||||
int cursor;
|
||||
bool constrained;
|
||||
bool pass_through;
|
||||
button * buttons;
|
||||
binding_list_t x_bindings[KEYMOD_MAX];
|
||||
binding_list_t y_bindings[KEYMOD_MAX];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Settings for a mouse.
|
||||
*/
|
||||
struct mouse {
|
||||
mouse ();
|
||||
virtual ~mouse ();
|
||||
int x;
|
||||
int y;
|
||||
int save_x;
|
||||
int save_y;
|
||||
SGPropertyNode_ptr mode_node;
|
||||
SGPropertyNode_ptr mouse_button_nodes[MAX_MOUSE_BUTTONS];
|
||||
int nModes;
|
||||
int current_mode;
|
||||
double timeout;
|
||||
mouse_mode * modes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize joystick bindings.
|
||||
*/
|
||||
void _init_joystick ();
|
||||
|
||||
|
||||
/**
|
||||
* Scan directory recursively for "named joystick" configuration files,
|
||||
* and read them into /input/joysticks/js-named[index]++.
|
||||
*/
|
||||
void _scan_joystick_dir (SGPath *path, SGPropertyNode* node, int *index);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize mouse bindings.
|
||||
*/
|
||||
void _init_mouse ();
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a single button.
|
||||
*/
|
||||
inline void _init_button (const SGPropertyNode * node,
|
||||
button &b,
|
||||
const string name);
|
||||
|
||||
/**
|
||||
* Initialize key bindings, as well as those joystick parts that
|
||||
* depend on a working Nasal subsystem.
|
||||
*/
|
||||
void _postinit_keyboard ();
|
||||
void _postinit_joystick ();
|
||||
|
||||
/**
|
||||
* Update the keyboard.
|
||||
*/
|
||||
void _update_keyboard ();
|
||||
|
||||
|
||||
/**
|
||||
* Update the joystick.
|
||||
*/
|
||||
void _update_joystick (double dt);
|
||||
|
||||
|
||||
/**
|
||||
* Update the mouse.
|
||||
*/
|
||||
void _update_mouse (double dt);
|
||||
|
||||
|
||||
/**
|
||||
* Update a single button.
|
||||
*/
|
||||
inline void _update_button (button &b, int modifiers, bool pressed,
|
||||
int x, int y);
|
||||
|
||||
|
||||
/**
|
||||
* Read bindings and modifiers.
|
||||
*/
|
||||
void _read_bindings (const SGPropertyNode * node,
|
||||
binding_list_t * binding_list,
|
||||
int modifiers);
|
||||
|
||||
/**
|
||||
* Look up the bindings for a key code.
|
||||
*/
|
||||
const binding_list_t& _find_key_bindings (unsigned int k,
|
||||
int modifiers);
|
||||
|
||||
button _key_bindings[MAX_KEYS];
|
||||
joystick _joystick_bindings[MAX_JOYSTICKS];
|
||||
mouse _mouse_bindings[MAX_MICE];
|
||||
|
||||
/**
|
||||
* Nasal module name/namespace.
|
||||
*/
|
||||
string _module;
|
||||
|
||||
/**
|
||||
* List of currently pressed mouse button events
|
||||
*/
|
||||
std::map<int, std::list<SGSharedPtr<SGPickCallback> > > _activePickCallbacks;
|
||||
|
||||
/**
|
||||
* Key listener interface.
|
||||
*/
|
||||
SGPropertyNode_ptr _key_event;
|
||||
int _key_code;
|
||||
int _key_modifiers;
|
||||
bool _key_pressed;
|
||||
bool _key_shift;
|
||||
bool _key_ctrl;
|
||||
bool _key_alt;
|
||||
bool _key_meta;
|
||||
bool _key_super;
|
||||
bool _key_hyper;
|
||||
};
|
||||
|
||||
#endif // _INPUT_HXX
|
||||
|
|
Loading…
Reference in a new issue