Make joysticks actually work

This commit is contained in:
Ilari Liusvaara 2011-09-18 01:26:45 +03:00
parent 6bb1685a36
commit faafcd2c7d
6 changed files with 1166 additions and 998 deletions

View file

@ -82,11 +82,6 @@ command::~command() throw()
void command::invokeC(const std::string& cmd) throw()
{
try {
if(command_stack.count(cmd)) {
messages << "Can not invoke recursively: " << cmd << std::endl;
return;
}
command_stack.insert(cmd);
std::string cmd2 = cmd;
if(cmd2 == "?") {
//The special ? command.
@ -94,7 +89,6 @@ void command::invokeC(const std::string& cmd) throw()
for(auto i = commands->begin(); i != commands->end(); ++i)
messages << i->first << ": " << i->second->get_short_help() << std::endl;
}
command_stack.erase(cmd);
return;
}
if(cmd2.length() > 1 && cmd2[0] == '?') {
@ -114,7 +108,6 @@ void command::invokeC(const std::string& cmd) throw()
size_t j = 0;
for(auto i = aliases[aname].begin(); i != aliases[aname].end(); ++i, ++j)
messages << "#" + (j + 1) << ": " << *i << std::endl;
command_stack.erase(cmd);
return;
}
}
@ -123,11 +116,9 @@ void command::invokeC(const std::string& cmd) throw()
if(!commands || !commands->count(rcmd)) {
if(rcmd != "")
messages << "Unknown command '" << rcmd << "'" << std::endl;
command_stack.erase(cmd);
return;
}
messages << (*commands)[rcmd]->get_long_help() << std::endl;
command_stack.erase(cmd);
return;
}
bool may_be_alias_expanded = true;
@ -138,7 +129,6 @@ void command::invokeC(const std::string& cmd) throw()
if(may_be_alias_expanded && aliases.count(cmd2)) {
for(auto i = aliases[cmd2].begin(); i != aliases[cmd2].end(); ++i)
invokeC(*i);
command_stack.erase(cmd);
return;
}
try {
@ -157,9 +147,11 @@ void command::invokeC(const std::string& cmd) throw()
cmdh = (*commands)[rcmd];
if(!cmdh) {
messages << "Unknown command '" << rcmd << "'" << std::endl;
command_stack.erase(cmd);
return;
}
if(command_stack.count(cmd))
throw std::runtime_error("Recursive command invocation");
command_stack.insert(cmd);
cmdh->invoke(args);
command_stack.erase(cmd);
return;

View file

@ -1,9 +1,10 @@
#include "keymapper.hpp"
#include <stdexcept>
#include "lua.hpp"
#include "window.hpp"
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <set>
#include "misc.hpp"
#include "memorymanip.hpp"
@ -30,7 +31,11 @@ namespace
command = t.tail();
if(command == "")
throw std::runtime_error("Expected command");
window::bind(mod, modmask, keyname, command);
keymapper::bind(mod, modmask, keyname, command);
if(mod != "" || modmask != "")
messages << mod << "/" << modmask << " ";
messages << keyname << " bound to '" << command << "'" << std::endl;
});
function_ptr_command<tokensplitter&> unbind_key("unbind-key", "Unbind a (pseudo-)key",
@ -51,13 +56,16 @@ namespace
command = t.tail();
if(command != "")
throw std::runtime_error("Unexpected argument");
window::unbind(mod, modmask, keyname);
keymapper::unbind(mod, modmask, keyname);
if(mod != "" || modmask != "")
messages << mod << "/" << modmask << " ";
messages << keyname << " unbound" << std::endl;
});
function_ptr_command<> show_bindings("show-bindings", "Show active bindings",
"Syntax: show-bindings\nShow bindings that are currently active.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
window::dumpbindings();
keymapper::dumpbindings();
});
}
@ -71,3 +79,424 @@ std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::ba
cmd[0] = '-';
return cmd;
}
namespace
{
std::map<std::string, modifier*>* known_modifiers;
std::map<std::string, std::string>* modifier_linkages;
std::map<std::string, keygroup*>* keygroups;
//Returns orig if not linked.
const modifier* get_linked_modifier(const modifier* orig)
{
if(!modifier_linkages || !modifier_linkages->count(orig->name()))
return orig;
std::string l = (*modifier_linkages)[orig->name()];
return (*known_modifiers)[l];
}
}
modifier::modifier(const std::string& name) throw(std::bad_alloc)
{
if(!known_modifiers)
known_modifiers = new std::map<std::string, modifier*>();
(*known_modifiers)[modname = name] = this;
}
modifier::modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc)
{
if(!known_modifiers)
known_modifiers = new std::map<std::string, modifier*>();
if(!modifier_linkages)
modifier_linkages = new std::map<std::string, std::string>();
(*known_modifiers)[modname = name] = this;
(*modifier_linkages)[name] = linkgroup;
}
modifier& modifier::lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error)
{
if(!known_modifiers || !known_modifiers->count(name)) {
std::ostringstream x;
x << "Invalid modifier '" << name << "'";
throw std::runtime_error(x.str());
}
return *(*known_modifiers)[name];
}
std::string modifier::name() const throw(std::bad_alloc)
{
return modname;
}
void modifier_set::add(const modifier& mod, bool really) throw(std::bad_alloc)
{
if(really)
set.insert(&mod);
}
void modifier_set::remove(const modifier& mod, bool really) throw(std::bad_alloc)
{
if(really)
set.erase(&mod);
}
modifier_set modifier_set::construct(const std::string& _modifiers) throw(std::bad_alloc, std::runtime_error)
{
modifier_set set;
std::string modifiers = _modifiers;
while(modifiers != "") {
std::string mod = modifiers;
std::string rest;
size_t split = modifiers.find_first_of(",");
if(split < modifiers.length()) {
mod = modifiers.substr(0, split);
rest = modifiers.substr(split + 1);
}
set.add(modifier::lookup(mod));
modifiers = rest;
}
return set;
}
bool modifier_set::valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc)
{
//No element can be together with its linkage group.
for(auto i = set.set.begin(); i != set.set.end(); ++i) {
const modifier* j = get_linked_modifier(*i);
if(*i != j && set.set.count(j))
return false;
}
for(auto i = mask.set.begin(); i != mask.set.end(); ++i) {
const modifier* j = get_linked_modifier(*i);
if(*i != j && mask.set.count(j))
return false;
}
//For every element of set, it or its linkage group must be in mask.
for(auto i = set.set.begin(); i != set.set.end(); ++i) {
const modifier* j = get_linked_modifier(*i);
if(!mask.set.count(*i) && !mask.set.count(j))
return false;
}
return true;
}
bool modifier_set::operator==(const modifier_set& m) const throw()
{
for(auto i = set.begin(); i != set.end(); ++i)
if(!m.set.count(*i))
return false;
for(auto i = m.set.begin(); i != m.set.end(); ++i)
if(!set.count(*i))
return false;
return true;
}
bool modifier_set::triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask)
throw(std::bad_alloc)
{
modifier_set unmet = trigger;
modifier_set blank;
for(auto i = set.set.begin(); i != set.set.end(); i++) {
auto linked = get_linked_modifier(*i);
if(mask.set.count(linked) && trigger.set.count(linked))
unmet.remove(*linked);
if(mask.set.count(linked) && trigger.set.count(*i))
unmet.remove(**i);
if(mask.set.count(*i) && trigger.set.count(*i))
unmet.remove(**i);
}
return (unmet == blank);
}
std::string keygroup::name() throw(std::bad_alloc)
{
return keyname;
}
keygroup::keygroup(const std::string& name, enum type t) throw(std::bad_alloc)
{
if(!keygroups)
keygroups = new std::map<std::string, keygroup*>();
(*keygroups)[keyname = name] = this;
ktype = t;
state = 0;
cal_left = -32768;
cal_center = 0;
cal_right = 32767;
cal_tolerance = 0.5;
}
void keygroup::change_type(enum type t)
{
ktype = t;
state = 0;
}
std::pair<keygroup*, unsigned> keygroup::lookup(const std::string& name) throw(std::bad_alloc,
std::runtime_error)
{
if(!keygroups)
throw std::runtime_error("Invalid key");
if(keygroups->count(name))
return std::make_pair((*keygroups)[name], 0);
std::string prefix = name;
char letter = prefix[prefix.length() - 1];
prefix = prefix.substr(0, prefix.length() - 1);
if(!keygroups->count(prefix))
throw std::runtime_error("Invalid key");
keygroup* g = (*keygroups)[prefix];
switch(letter) {
case '+':
case 'n':
return std::make_pair(g, 0);
case '-':
case 'e':
return std::make_pair(g, 1);
case 's':
return std::make_pair(g, 2);
case 'w':
return std::make_pair(g, 3);
default:
throw std::runtime_error("Invalid key");
}
}
void keygroup::change_calibration(short left, short center, short right, double tolerance)
{
cal_left = left;
cal_center = center;
cal_right = right;
cal_tolerance = tolerance;
}
double keygroup::compensate(short value)
{
if(ktype == KT_HAT || ktype == KT_KEY || ktype == KT_DISABLED)
return value; //These can't be calibrated.
if(value <= cal_left)
return -1.0;
else if(value >= cal_right)
return 1.0;
else if(value == cal_center)
return 0.0;
else if(value < cal_center)
return (static_cast<double>(value) - cal_center) / (static_cast<double>(cal_center) - cal_left);
else
return (static_cast<double>(value) - cal_center) / (static_cast<double>(cal_right) - cal_center);
}
double keygroup::compensate2(double value)
{
switch(ktype) {
case KT_DISABLED:
return 0; //Always neutral.
case KT_KEY:
case KT_HAT:
return value; //No mapping.
case KT_PRESSURE_0M:
return -value;
case KT_PRESSURE_0P:
return value;
case KT_PRESSURE_M0:
return 1 + value;
case KT_PRESSURE_MP:
return (1 + value) / 2;
case KT_PRESSURE_P0:
return 1 - value;
case KT_PRESSURE_PM:
return (1 - value) / 2;
case KT_AXIS_PAIR:
return value;
case KT_AXIS_PAIR_INVERSE:
return -value;
};
}
void keygroup::set_position(short pos, const modifier_set& modifiers) throw()
{
double x = compensate2(compensate(pos));
unsigned tmp;
bool left, right, up, down;
bool oleft, oright, oup, odown;
switch(ktype) {
case KT_DISABLED:
return;
case KT_KEY:
case KT_PRESSURE_0M:
case KT_PRESSURE_0P:
case KT_PRESSURE_M0:
case KT_PRESSURE_MP:
case KT_PRESSURE_P0:
case KT_PRESSURE_PM:
tmp = (x >= cal_tolerance);
run_listeners(modifiers, 0, true, (!state && tmp), x);
run_listeners(modifiers, 0, false, (state && !tmp), x);
state = tmp;
break;
case KT_AXIS_PAIR:
case KT_AXIS_PAIR_INVERSE:
if(x <= -cal_tolerance)
tmp = 2;
else if(x >= cal_tolerance)
tmp = 1;
else
tmp = 0;
run_listeners(modifiers, 0, false, state == 1 && tmp != 1, x);
run_listeners(modifiers, 1, false, state == 2 && tmp != 2, x);
run_listeners(modifiers, 0, true, tmp == 1 && state != 1, x);
run_listeners(modifiers, 1, true, tmp == 2 && state != 2, x);
state = tmp;
break;
case KT_HAT:
left = ((pos & 8) != 0);
right = ((pos & 2) != 0);
up = ((pos & 1) != 0);
down = ((pos & 4) != 0);
oleft = ((state & 8) != 0);
oright = ((state & 2) != 0);
oup = ((state & 1) != 0);
odown = ((state & 4) != 0);
run_listeners(modifiers, 3, false, oleft && !left, x);
run_listeners(modifiers, 1, false, oright && !right, x);
run_listeners(modifiers, 0, false, oup && !up, x);
run_listeners(modifiers, 2, false, odown && !down, x);
run_listeners(modifiers, 2, true, !odown && down, x);
run_listeners(modifiers, 0, true, !oup && up, x);
run_listeners(modifiers, 1, true, !oright && right, x);
run_listeners(modifiers, 3, true, !oleft && left, x);
state = pos;
break;
}
}
void keygroup::add_key_listener(key_listener& l) throw(std::bad_alloc)
{
listeners.push_back(&l);
}
void keygroup::remove_key_listener(key_listener& l) throw(std::bad_alloc)
{
for(auto i = listeners.begin(); i != listeners.end(); ++i)
if(*i == &l) {
listeners.erase(i);
return;
}
}
void keygroup::run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x)
{
if(!really)
return;
std::string name = keyname;
if(ktype == KT_AXIS_PAIR && subkey == 0)
name = name + "+";
if(ktype == KT_AXIS_PAIR && subkey == 1)
name = name + "-";
if(ktype == KT_HAT && subkey == 0)
name = name + "n";
if(ktype == KT_HAT && subkey == 1)
name = name + "e";
if(ktype == KT_HAT && subkey == 2)
name = name + "s";
if(ktype == KT_HAT && subkey == 3)
name = name + "w";
if(exclusive) {
exclusive->key_event(modifiers, *this, subkey, polarity, name);
return;
}
for(auto i = listeners.begin(); i != listeners.end(); ++i)
(*i)->key_event(modifiers, *this, subkey, polarity, name);
}
keygroup::key_listener* keygroup::exclusive;
void keygroup::set_exclusive_key_listener(key_listener* l) throw()
{
exclusive = l;
}
namespace
{
struct triple
{
triple(const std::string& _a, const std::string& _b, const std::string& _c)
{
a = _a;
b = _b;
c = _c;
}
std::string a;
std::string b;
std::string c;
bool operator==(const triple& t) const
{
bool x = (a == t.a && b == t.b && c == t.c);
return x;
}
bool operator<(const triple& t) const
{
bool x = (a < t.a || (a == t.a && b < t.b) || (a == t.a && b == t.b && c < t.c));
return x;
}
};
struct keybind_data : public keygroup::key_listener
{
modifier_set mod;
modifier_set modmask;
keygroup* group;
unsigned subkey;
std::string command;
void key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, bool polarity,
const std::string& name)
{
if(!modifier_set::triggers(modifiers, mod, modmask))
return;
std::string cmd = fixup_command_polarity(command, polarity);
if(cmd == "")
return;
command::invokeC(cmd);
}
};
std::map<triple, keybind_data> keybindings;
}
void keymapper::bind(std::string mod, std::string modmask, std::string keyname, std::string command)
throw(std::bad_alloc, std::runtime_error)
{
triple k(mod, modmask, keyname);
modifier_set _mod = modifier_set::construct(mod);
modifier_set _modmask = modifier_set::construct(modmask);
if(!modifier_set::valid(_mod, _modmask))
throw std::runtime_error("Invalid modifiers");
auto g = keygroup::lookup(keyname);
if(!keybindings.count(k)) {
keybindings[k].mod = _mod;
keybindings[k].modmask = _modmask;
keybindings[k].group = g.first;
keybindings[k].subkey = g.second;
g.first->add_key_listener(keybindings[k]);
}
keybindings[k].command = command;
}
void keymapper::unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error)
{
triple k(mod, modmask, keyname);
if(!keybindings.count(k))
throw std::runtime_error("Key is not bound");
keybindings[k].group->remove_key_listener(keybindings[k]);
keybindings.erase(k);
}
void keymapper::dumpbindings() throw(std::bad_alloc)
{
for(auto i = keybindings.begin(); i != keybindings.end(); ++i) {
messages << "bind-key ";
if(i->first.a != "" || i->first.b != "")
messages << i->first.a << "/" << i->first.b << " ";
messages << i->first.c << std::endl;
}
}

View file

@ -10,143 +10,225 @@
#include "misc.hpp"
/**
* \brief Fixup command according to key polarity.
*
* Takes in a raw command and returns the command that should be actually executed given the key polarity.
*
* \param cmd Raw command.
* \param polarity Polarity (True => Being pressed, False => Being released).
* \return The fixed command, "" if no command should be executed.
* \throws std::bad_alloc Not enough memory.
* parameter cmd: Raw command.
* parameter polarity: Polarity (True => Being pressed, False => Being released).
* returns: The fixed command, "" if no command should be executed.
* throws std::bad_alloc: Not enough memory.
*/
std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc);
/**
* \brief Keyboard mapper.
*
* This class handles internals of mapping events from keyboard buttons and pseudo-buttons. The helper class T has
* to have the following:
*
* unsigned T::mod_str(const std::string& mod): Translate modifiers set mod into modifier mask.
* typedef T::internal_keysymbol: Key symbol to match against. Needs to have == operator available.
* T::internal_keysymbol key_str(const std::string& keyname): Translate key name to key to match against.
* typedef T::keysymbol: Key symbol from keyboard (or pseudo-button). Carries modifiers too.
* unsigned mod_key(T::keysymbol key): Get modifier mask for keyboard key.
* T::internal_keysymbol key_key(T::keysymbol key): Get key symbol to match against for given keyboard key.
* std::string T::name_key(unsigned mod, unsigned modmask, T::internal_keysymbol key): Print name of key with mods.
* Modifier.
*/
class modifier
{
public:
/**
* Create modifier.
*/
modifier(const std::string& name) throw(std::bad_alloc);
/**
* Create linked modifier.
*/
modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc);
/**
* Look up a modifier.
*/
static modifier& lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error);
/**
* Get name of modifier.
*/
std::string name() const throw(std::bad_alloc);
private:
modifier(const modifier&);
modifier& operator=(const modifier&);
std::string modname;
};
/**
* Set of modifiers.
*/
class modifier_set
{
public:
/**
* Add a modifier.
*/
void add(const modifier& mod, bool really = true) throw(std::bad_alloc);
/**
* Remove a modifier.
*/
void remove(const modifier& mod, bool really = true) throw(std::bad_alloc);
/**
* Construct set from string.
*/
static modifier_set construct(const std::string& modifiers) throw(std::bad_alloc, std::runtime_error);
/**
* Check modifier against its mask for validity.
*/
static bool valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc);
/**
* Check if this modifier set triggers the action.
*/
static bool triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask)
throw(std::bad_alloc);
/**
* Equality.
*/
bool operator==(const modifier_set& m) const throw();
private:
std::set<const modifier*> set;
};
/**
* Key or key group.
*/
class keygroup
{
public:
/**
* Key group type.
*/
enum type
{
/**
* Disabled.
*/
KT_DISABLED,
/**
* Singular button.
*/
KT_KEY,
/**
* Pressure-sensitive button
*/
KT_PRESSURE_PM,
KT_PRESSURE_MP,
KT_PRESSURE_0P,
KT_PRESSURE_0M,
KT_PRESSURE_P0,
KT_PRESSURE_M0,
/**
* Axis key pair.
*/
KT_AXIS_PAIR,
KT_AXIS_PAIR_INVERSE,
/**
* Hat.
*/
KT_HAT
};
/**
* Create new key group.
*/
keygroup(const std::string& name, enum type t) throw(std::bad_alloc);
/**
* Change type of key group.
*/
void change_type(enum type t);
/**
* Change calibration (Axis pairs and pressure buttons only).
*/
void change_calibration(short left, short center, short right, double tolerance);
/**
* Change state of this key group.
*
* For KT_KEY, value is zero/nonzero.
* For KT_PRESSURE_* and KT_AXIS_PAIR*, value is -32768...32767.
* For KT_HAT, 1 is up, 2 is right, 4 is down, 8 is left (may be ORed).
*/
void set_position(short pos, const modifier_set& modifiers) throw();
/**
* Look up key by name.
*/
static std::pair<keygroup*, unsigned> lookup(const std::string& name) throw(std::bad_alloc,
std::runtime_error);
/**
* Look up key name.
*/
std::string name() throw(std::bad_alloc);
/**
* Keyboard key listener.
*/
struct key_listener
{
/**
* Invoked on key.
*/
virtual void key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name) = 0;
};
/**
* Add key listener.
*/
void add_key_listener(key_listener& l) throw(std::bad_alloc);
/**
* Remove key listener.
*/
void remove_key_listener(key_listener& l) throw(std::bad_alloc);
/**
* Excelusive key listener.
*/
static void set_exclusive_key_listener(key_listener* l) throw();
private:
unsigned state;
enum type ktype;
short cal_left;
short cal_center;
short cal_right;
double cal_tolerance;
double compensate(short value);
double compensate2(double value);
void run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x);
std::list<key_listener*> listeners;
std::string keyname;
static key_listener* exclusive;
};
/**
* This class handles internals of mapping events from keyboard buttons and pseudo-buttons.
*
*/
template<class T>
class keymapper
{
public:
/**
* \brief Bind a key.
*
* Binds a key, erroring out if binding would conflict with existing one.
*
* \param mod Modifier set to require to be pressed.
* \param modmask Modifier set to take into account.
* \param keyname Key to bind the action to.
* \param command The command to bind.
* \throws std::bad_alloc Not enough memory.
* \throws std::runtime_error The binding would conflict with existing one.
* parameter mod: Modifier set to require to be pressed.
* parameter modmask: Modifier set to take into account.
* parameter keyname: Key to bind the action to.
* parameter command: The command to bind.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: The binding would conflict with existing one or invalid modifier/key.
*/
void bind(std::string mod, std::string modmask, std::string keyname, std::string command) throw(std::bad_alloc,
std::runtime_error)
{
unsigned _mod = T::mod_str(mod);
unsigned _modmask = T::mod_str(modmask);
if(_mod & ~_modmask)
throw std::runtime_error("Mod must be subset of modmask");
typename T::internal_keysymbol _keyname = T::key_str(keyname);
/* Check for collisions. */
for(auto i = bindings.begin(); i != bindings.end(); i++) {
if(!(_keyname == i->symbol))
continue;
if((_mod & _modmask & i->modmask) != (i->mod & _modmask & i->modmask))
continue;
throw std::runtime_error("Would conflict with " + T::name_key(i->mod, i->modmask, i->symbol));
}
struct kdata k;
k.mod = _mod;
k.modmask = _modmask;
k.symbol = _keyname;
k.command = command;
bindings.push_back(k);
}
static void bind(std::string mod, std::string modmask, std::string keyname, std::string command)
throw(std::bad_alloc, std::runtime_error);
/**
* \brief Unbind a key.
*
* Unbinds a key, erroring out if binding does not exist..
*
* \param mod Modifier set to require to be pressed.
* \param modmask Modifier set to take into account.
* \param keyname Key to bind the action to.
* \throws std::bad_alloc Not enough memory.
* \throws std::runtime_error The binding does not exist.
* parameter mod: Modifier set to require to be pressed.
* parameter modmask: Modifier set to take into account.
* parameter keyname: Key to bind the action to.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: The binding does not exist.
*/
void unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error)
{
unsigned _mod = T::mod_str(mod);
unsigned _modmask = T::mod_str(modmask);
typename T::internal_keysymbol _keyname = T::key_str(keyname);
for(auto i = bindings.begin(); i != bindings.end(); i++) {
if(!(_keyname == i->symbol) || _mod != i->mod || _modmask != i->modmask)
continue;
bindings.erase(i);
return;
}
throw std::runtime_error("No such binding");
}
static void unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error);
/**
* \brief Map key symbol from keyboard + polarity into a command.
* Dump list of bindigns as message to console.
*
* Takes in symbol from keyboard and polarity. Outputs command to run.
*
* \param sym Symbol from keyboard (with its mods).
* \param polarity True if key is being pressed, false if being released.
* \return The command to run. "" if none.
* \throws std::bad_alloc Not enough memory.
* throws std::bad_alloc: Not enough memory.
*/
std::string map(typename T::keysymbol sym, bool polarity) throw(std::bad_alloc)
{
unsigned _mod = T::mod_key(sym);
typename T::internal_keysymbol _keyname = T::key_key(sym);
for(auto i = bindings.begin(); i != bindings.end(); i++) {
if((!(_keyname == i->symbol)) || ((_mod & i->modmask) != (i->mod & i->modmask)))
continue;
std::string x = fixup_command_polarity(i->command, polarity);
if(x == "")
continue;
return x;
}
return "";
}
/**
* \brief Dump list of bindigns as messages to specified graphics handle.
*
* \throws std::bad_alloc Not enough memory.
*/
void dumpbindings() throw(std::bad_alloc)
{
for(auto i = bindings.begin(); i != bindings.end(); i++)
messages << "bind " << T::name_key(i->mod, i->modmask, i->symbol) << " " << i->command
<< std::endl;
}
private:
struct kdata
{
unsigned mod;
unsigned modmask;
typename T::internal_keysymbol symbol;
std::string command;
};
std::list<kdata> bindings;
static void dumpbindings() throw(std::bad_alloc);
};
#endif

View file

@ -1666,6 +1666,88 @@ scroll-down
Scroll messages window forward one screenful.
\end_layout
\begin_layout Subsubsection
axismode <axis> <mode>
\end_layout
\begin_layout Standard
Set joystick axis mode.
<axis> is of form
\begin_inset Quotes eld
\end_inset
joystick<num>axis<axis>
\begin_inset Quotes erd
\end_inset
, e.g.
\begin_inset Quotes eld
\end_inset
joystick0axis5
\begin_inset Quotes erd
\end_inset
.
Mode is one of:
\end_layout
\begin_layout Itemize
axis: Normal axis mode
\end_layout
\begin_layout Itemize
axis_inverse: Inverse axis mode.
\end_layout
\begin_layout Itemize
pressure_0m: Pressure sensitive.
Released at 0, pressed at full negative.
\end_layout
\begin_layout Itemize
pressure_0p: Pressure sensitive.
Released at 0, pressed at full positive.
\end_layout
\begin_layout Itemize
pressure_m0: Pressure sensitive.
Released at full negative, pressed at 0.
\end_layout
\begin_layout Itemize
pressure_mp: Pressure sensitive.
Released at full negative, pressed at full positive.
\end_layout
\begin_layout Itemize
pressure_p0: Pressure sensitive.
Released at full positive, pressed at 0.
\end_layout
\begin_layout Itemize
pressure_pm: Pressure sensitive.
Released at full positive, pressed at full negative.
\end_layout
\begin_layout Standard
Note that if you have Wired Microsoft XBox 360 controller (works great in
Linux, BTW), you might want to do the following:
\end_layout
\begin_layout Itemize
axismode joystick0axis2 pressure_mp
\end_layout
\begin_layout Itemize
axismode joystick0axis5 pressure_mp
\end_layout
\begin_layout Standard
Since axes 2 and 5 are LT/RT, which are pressure sensitive.
\end_layout
\begin_layout Subsection
Settings
\end_layout

File diff suppressed because it is too large Load diff

View file

@ -67,38 +67,6 @@ public:
*/
static void fatal_error() throw();
/**
* Bind a key.
*
* parameter mod: Set of modifiers.
* parameter modmask: Modifier mask (set of modifiers).
* parameter keyname: Name of key or pseudo-key.
* parameter command: Command to run.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Invalid key or modifier name, or conflict.
*/
static void bind(std::string mod, std::string modmask, std::string keyname, std::string command)
throw(std::bad_alloc, std::runtime_error);
/**
* Unbind a key.
*
* parameter mod: Set of modifiers.
* parameter modmask: Modifier mask (set of modifiers).
* parameter keyname: Name of key or pseudo-key.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Invalid key or modifier name, or not bound.
*/
static void unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error);
/**
* Dump bindings into this window.
*
* throws std::bad_alloc: Not enough memory.
*/
static void dumpbindings() throw(std::bad_alloc);
/**
* Processes inputs. If in non-modal mode (normal mode without pause), this returns quickly. Otherwise it waits
* for modal mode to exit.