lsnes/include/library/keyboard-mapper.hpp
2014-05-18 00:38:58 +03:00

458 lines
10 KiB
C++

#ifndef _library__keyboard_mapper__hpp__included__
#define _library__keyboard_mapper__hpp__included__
#include <set>
#include <list>
#include <stdexcept>
#include <string>
#include "keyboard.hpp"
namespace command
{
class group;
}
namespace keyboard
{
class invbind;
class ctrlrkey;
std::pair<key*, unsigned> keymapper_lookup_subkey(keyboard& kbd, const std::string& name,
bool axis) throw(std::bad_alloc, std::runtime_error);
/**
* Key specifier
*/
struct keyspec
{
/**
* Create a new key specifier (invalid).
*/
keyspec() throw(std::bad_alloc);
/**
* Create a new key specifier from keyspec.
*
* Parameter keyspec: The key specifier.
*/
keyspec(const std::string& keyspec) throw(std::bad_alloc, std::runtime_error);
/**
* Get the key specifier as a keyspec.
*/
operator std::string() throw(std::bad_alloc);
/**
* Is valid?
*/
operator bool() throw();
/**
* Is not valid?
*/
bool operator!() throw();
/**
* Clear the keyspec.
*/
void clear() throw();
/**
* Compare for equality.
*/
bool operator==(const keyspec& keyspec);
/**
* Compare for not-equality.
*/
bool operator!=(const keyspec& keyspec);
/**
* The modifier.
*/
std::string mod;
/**
* The mask.
*/
std::string mask;
/**
* The key itself.
*/
std::string key;
};
class invbind_set;
class invbind_info;
class invbind_info;
/**
* Inverse bind set.
*/
class invbind_set
{
public:
/**
* Set add/drop listener.
*/
class listener
{
public:
/**
* Dtor.
*/
virtual ~listener();
/**
* New item in set.
*/
virtual void create(invbind_set& s, const std::string& name, invbind_info& ibinfo) = 0;
/**
* Deleted item from set.
*/
virtual void destroy(invbind_set& s, const std::string& name) = 0;
/**
* Destroyed the entiere set.
*/
virtual void kill(invbind_set& s) = 0;
};
/**
* Create a set.
*/
invbind_set();
/**
* Destructor.
*/
~invbind_set();
/**
* Register a inverse bind.
*/
void do_register(const std::string& name, invbind_info& info);
/**
* Unregister a inverse bind.
*/
void do_unregister(const std::string& name, invbind_info& info);
/**
* Add a callback on new invese bind.
*/
void add_callback(listener& listener) throw(std::bad_alloc);
/**
* Drop a callback on new inverse bind.
*/
void drop_callback(listener& listener);
};
/**
* Keyboard mapper. Maps keyboard keys into commands.
*/
class mapper : public event_listener
{
public:
/**
* Create new keyboard mapper.
*/
mapper(keyboard& kbd, command::group& domain) throw(std::bad_alloc);
/**
* Destroy a keyboard mapper.
*/
~mapper() throw();
/**
* Binds a key, erroring out if 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);
/**
* Unbinds a key, erroring out if 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);
/**
* Get keys bound.
*
* Returns: The set of keyspecs that are bound.
*/
std::list<keyspec> get_bindings() throw(std::bad_alloc);
/**
* Get command for key.
*/
std::string get(const keyspec& keyspec) throw(std::bad_alloc);
/**
* Bind command for key.
*
* Parameter keyspec: The key specifier to bind to.
* Parameter cmd: The command to bind. If "", the key is unbound.
*/
void set(const keyspec& keyspec, const std::string& cmd) throw(std::bad_alloc, std::runtime_error);
/**
* Get set of inverse binds.
*
* Returns: The set of all inverses.
*/
std::set<invbind*> get_inverses() throw(std::bad_alloc);
/**
* Find inverse bind by command.
*
* Parameter command: The command.
* Returns: The inverse bind, or NULL if none.
*/
invbind* get_inverse(const std::string& command) throw(std::bad_alloc);
/**
* Get set of controller keys.
*
* Returns: The set of all controller keys.
*/
std::set<ctrlrkey*> get_controller_keys() throw(std::bad_alloc);
/**
* Get specific controller key.
*/
ctrlrkey* get_controllerkey(const std::string& command) throw(std::bad_alloc);
/**
* Get list of controller keys for specific keyboard key.
*/
std::list<ctrlrkey*> get_controllerkeys_kbdkey(key* kbdkey) throw(std::bad_alloc);
/**
* Register inverse bind.
*/
void do_register(const std::string& name, invbind& bind) throw(std::bad_alloc);
/**
* Unregister inverse bind.
*/
void do_unregister(const std::string& name, invbind& bind) throw(std::bad_alloc);
/**
* Register controller key.
*/
void do_register(const std::string& name, ctrlrkey& ckey) throw(std::bad_alloc);
/**
* Unregister inverse bind.
*/
void do_unregister(const std::string& name, ctrlrkey& ckey) throw(std::bad_alloc);
/**
* Get keyboard.
*/
keyboard& get_keyboard() throw();
/**
* Get command group to run commands in..
*/
command::group& get_command_group() throw();
/**
* Fixup command based on polarity.
*
* Parameter cmd: The raw command.
* Parameter polarity: Polarity (true is rising edge, false is falling edge).
* Returns: The fixed command, or "" if nothing should be run.
*/
static std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc);
/**
* Add a set of inverse binds.
*/
void add_invbind_set(invbind_set& set);
/**
* Drop a set of inverse binds.
*/
void drop_invbind_set(invbind_set& set);
/**
* Key triplet.
*/
struct triplet
{
triplet(modifier_set mod, modifier_set mask, key& kkey, unsigned subkey);
triplet(key& kkey, unsigned subkey);
triplet(keyboard& k, const keyspec& spec);
bool operator<(const struct triplet& a) const;
bool operator==(const struct triplet& a) const;
bool operator<=(const struct triplet& a) const { return !(a > *this); }
bool operator!=(const struct triplet& a) const { return !(a == *this); }
bool operator>=(const struct triplet& a) const { return !(a < *this); }
bool operator>(const struct triplet& a) const { return (a < *this); }
keyspec as_keyspec() const throw(std::bad_alloc);
bool index;
modifier_set mod;
modifier_set mask;
key* _key;
unsigned subkey;
};
private:
class listener : public invbind_set::listener
{
public:
listener(mapper& _grp);
~listener();
void create(invbind_set& s, const std::string& name, invbind_info& ibinfo);
void destroy(invbind_set& s, const std::string& name);
void kill(invbind_set& s);
private:
mapper& grp;
} _listener;
void change_command(const keyspec& spec, const std::string& old, const std::string& newc);
void on_key_event(modifier_set& mods, key& key, event& event);
void on_key_event_subkey(modifier_set& mods, key& key, unsigned skey, bool polarity);
mapper(const mapper&);
mapper& operator=(const mapper&);
std::set<key*> listening;
keyboard& kbd;
command::group& domain;
};
/**
* Inverse bind info.
*/
class invbind_info
{
public:
/**
* Create inverse bind.
*
* Parameter set: The set to be in.
* Parameter _command: Command this is for.
* Parameter _name: Name of inverse key.
*/
invbind_info(invbind_set& set, const std::string& _command, const std::string& _name)
throw(std::bad_alloc);
/**
* Destructor.
*/
~invbind_info() throw();
/**
* Make inverse bind out of this.
*/
invbind* make(mapper& m);
/**
* Notify set dying.
*/
void set_died();
private:
invbind_set* in_set;
std::string command;
std::string name;
};
/**
* Inverse bind. Can map up to 2 keys to some command (and follows forward binds).
*/
class invbind
{
public:
/**
* Create inverse bind.
*
* Parameter mapper: The keyboard mapper to follow.
* Parameter command: Command this is for.
* Parameter name: Name of inverse key.
*/
invbind(mapper& kmapper, const std::string& command, const std::string& name, bool dynamic = false)
throw(std::bad_alloc);
/**
* Destructor.
*/
~invbind() throw();
/**
* Get keyspec.
*
* Parameter index: Index of the keyspec to get.
* Returns: The keyspec.
*/
keyspec get(unsigned index) throw(std::bad_alloc);
/**
* Clear key (subsequent keys fill the gap).
*
* Parameter index: Index of key to clear.
*/
void clear(unsigned index) throw(std::bad_alloc);
/**
* Add key to set.
*
* Parameter keyspec: The new keyspec.
*/
void append(const keyspec& keyspec) throw(std::bad_alloc);
/**
* Get name for command.
*
* Returns: The name.
*/
std::string getname() throw(std::bad_alloc);
/**
* Notify mapper dying.
*/
void mapper_died();
private:
friend class mapper;
invbind(const invbind&);
invbind& operator=(const invbind&);
void addkey(const keyspec& keyspec);
mapper* _mapper;
std::string cmd;
std::string oname;
std::vector<keyspec> specs;
bool is_dynamic;
};
/**
* A controller key.
*
* Can overlap with any other bind.
*/
class ctrlrkey : public event_listener
{
public:
/**
* Create a new controller key.
*
* Parameter mapper: The keyboard mapper to follow.
* Parameter command: Command to run.
* Parameter name: Name of controller key.
* Parameter axis: If true, create a axis-type key.
*/
ctrlrkey(mapper& kmapper, const std::string& command, const std::string& name,
bool axis = false) throw(std::bad_alloc);
/**
* Destructor.
*/
~ctrlrkey() throw();
/**
* Get the trigger key.
*/
std::pair<key*, unsigned> get(unsigned index) throw();
/**
* Get the trigger key.
*/
std::string get_string(unsigned index) throw(std::bad_alloc);
/**
* Set the trigger key (appends).
*/
void append(key* key, unsigned subkey) throw();
/**
* Set the trigger key (appends).
*/
void append(const std::string& key) throw(std::bad_alloc, std::runtime_error);
/**
* Remove the trigger key.
*/
void remove(key* key, unsigned subkey) throw();
/**
* Get the command.
*/
const std::string& get_command() const throw() { return cmd; }
/**
* Get the name.
*/
const std::string& get_name() const throw() { return oname; }
/**
* Is axis-type?
*/
bool is_axis() const throw() { return axis; }
private:
void on_key_event(modifier_set& mods, key& key, event& event);
mapper& _mapper;
std::string cmd;
std::string oname;
std::vector<std::pair<key*, unsigned>> keys;
bool axis;
};
}
#endif