lsnes rr0-β2
[lsnes.git] / keymapper.hpp
blobcaae2bb4b977ee8a14ac17ff103bce14b2e4901c
1 #ifndef _keymapper__hpp__included__
2 #define _keymapper__hpp__included__
4 #include <string>
5 #include <sstream>
6 #include <stdexcept>
7 #include <list>
8 #include <set>
9 #include <iostream>
10 #include "misc.hpp"
12 /**
13 * \brief Fixup command according to key polarity.
15 * Takes in a raw command and returns the command that should be actually executed given the key polarity.
17 * \param cmd Raw command.
18 * \param polarity Polarity (True => Being pressed, False => Being released).
19 * \return The fixed command, "" if no command should be executed.
20 * \throws std::bad_alloc Not enough memory.
22 std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc);
25 /**
26 * \brief Keyboard mapper.
28 * This class handles internals of mapping events from keyboard buttons and pseudo-buttons. The helper class T has
29 * to have the following:
31 * unsigned T::mod_str(const std::string& mod): Translate modifiers set mod into modifier mask.
32 * typedef T::internal_keysymbol: Key symbol to match against. Needs to have == operator available.
33 * T::internal_keysymbol key_str(const std::string& keyname): Translate key name to key to match against.
34 * typedef T::keysymbol: Key symbol from keyboard (or pseudo-button). Carries modifiers too.
35 * unsigned mod_key(T::keysymbol key): Get modifier mask for keyboard key.
36 * T::internal_keysymbol key_key(T::keysymbol key): Get key symbol to match against for given keyboard key.
37 * std::string T::name_key(unsigned mod, unsigned modmask, T::internal_keysymbol key): Print name of key with mods.
39 template<class T>
40 class keymapper
42 public:
43 /**
44 * \brief Bind a key.
46 * Binds a key, erroring out if binding would conflict with existing one.
48 * \param mod Modifier set to require to be pressed.
49 * \param modmask Modifier set to take into account.
50 * \param keyname Key to bind the action to.
51 * \param command The command to bind.
52 * \throws std::bad_alloc Not enough memory.
53 * \throws std::runtime_error The binding would conflict with existing one.
55 void bind(std::string mod, std::string modmask, std::string keyname, std::string command) throw(std::bad_alloc,
56 std::runtime_error)
58 unsigned _mod = T::mod_str(mod);
59 unsigned _modmask = T::mod_str(modmask);
60 if(_mod & ~_modmask)
61 throw std::runtime_error("Mod must be subset of modmask");
62 typename T::internal_keysymbol _keyname = T::key_str(keyname);
63 /* Check for collisions. */
64 for(auto i = bindings.begin(); i != bindings.end(); i++) {
65 if(!(_keyname == i->symbol))
66 continue;
67 if((_mod & _modmask & i->modmask) != (i->mod & _modmask & i->modmask))
68 continue;
69 throw std::runtime_error("Would conflict with " + T::name_key(i->mod, i->modmask, i->symbol));
71 struct kdata k;
72 k.mod = _mod;
73 k.modmask = _modmask;
74 k.symbol = _keyname;
75 k.command = command;
76 bindings.push_back(k);
79 /**
80 * \brief Unbind a key.
82 * Unbinds a key, erroring out if binding does not exist..
84 * \param mod Modifier set to require to be pressed.
85 * \param modmask Modifier set to take into account.
86 * \param keyname Key to bind the action to.
87 * \throws std::bad_alloc Not enough memory.
88 * \throws std::runtime_error The binding does not exist.
90 void unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
91 std::runtime_error)
93 unsigned _mod = T::mod_str(mod);
94 unsigned _modmask = T::mod_str(modmask);
95 typename T::internal_keysymbol _keyname = T::key_str(keyname);
96 for(auto i = bindings.begin(); i != bindings.end(); i++) {
97 if(!(_keyname == i->symbol) || _mod != i->mod || _modmask != i->modmask)
98 continue;
99 bindings.erase(i);
100 return;
102 throw std::runtime_error("No such binding");
106 * \brief Map key symbol from keyboard + polarity into a command.
108 * Takes in symbol from keyboard and polarity. Outputs command to run.
110 * \param sym Symbol from keyboard (with its mods).
111 * \param polarity True if key is being pressed, false if being released.
112 * \return The command to run. "" if none.
113 * \throws std::bad_alloc Not enough memory.
115 std::string map(typename T::keysymbol sym, bool polarity) throw(std::bad_alloc)
117 unsigned _mod = T::mod_key(sym);
118 typename T::internal_keysymbol _keyname = T::key_key(sym);
119 for(auto i = bindings.begin(); i != bindings.end(); i++) {
120 if((!(_keyname == i->symbol)) || ((_mod & i->modmask) != (i->mod & i->modmask)))
121 continue;
122 std::string x = fixup_command_polarity(i->command, polarity);
123 if(x == "")
124 continue;
125 return x;
127 return "";
131 * \brief Dump list of bindigns as messages to specified graphics handle.
133 * \throws std::bad_alloc Not enough memory.
135 void dumpbindings() throw(std::bad_alloc)
137 for(auto i = bindings.begin(); i != bindings.end(); i++)
138 messages << "bind " << T::name_key(i->mod, i->modmask, i->symbol) << " " << i->command
139 << std::endl;
141 private:
142 struct kdata
144 unsigned mod;
145 unsigned modmask;
146 typename T::internal_keysymbol symbol;
147 std::string command;
149 std::list<kdata> bindings;
152 #endif