Make joysticks actually work
[lsnes.git] / keymapper.cpp
blob8e1b92ba157041bdef40aff4b6f092f0fdddc162
1 #include "keymapper.hpp"
2 #include <stdexcept>
3 #include "lua.hpp"
4 #include <iostream>
5 #include <list>
6 #include <map>
7 #include <sstream>
8 #include <set>
9 #include "misc.hpp"
10 #include "memorymanip.hpp"
11 #include "command.hpp"
13 namespace
15 function_ptr_command<tokensplitter&> bind_key("bind-key", "Bind a (pseudo-)key",
16 "Syntax: bind-key [<mod>/<modmask>] <key> <command>\nBind command to specified key (with specified "
17 " modifiers)\n",
18 [](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
19 std::string mod, modmask, keyname, command;
20 std::string mod_or_key = t;
21 if(mod_or_key.find_first_of("/") < mod_or_key.length()) {
22 //Mod field.
23 size_t split = mod_or_key.find_first_of("/");
24 mod = mod_or_key.substr(0, split);
25 modmask = mod_or_key.substr(split + 1);
26 mod_or_key = static_cast<std::string>(t);
28 if(mod_or_key == "")
29 throw std::runtime_error("Expected optional modifiers and key");
30 keyname = mod_or_key;
31 command = t.tail();
32 if(command == "")
33 throw std::runtime_error("Expected command");
34 keymapper::bind(mod, modmask, keyname, command);
35 if(mod != "" || modmask != "")
36 messages << mod << "/" << modmask << " ";
37 messages << keyname << " bound to '" << command << "'" << std::endl;
39 });
41 function_ptr_command<tokensplitter&> unbind_key("unbind-key", "Unbind a (pseudo-)key",
42 "Syntax: unbind-key [<mod>/<modmask>] <key>\nUnbind specified key (with specified modifiers)\n",
43 [](tokensplitter& t) throw(std::bad_alloc, std::runtime_error) {
44 std::string mod, modmask, keyname, command;
45 std::string mod_or_key = t;
46 if(mod_or_key.find_first_of("/") < mod_or_key.length()) {
47 //Mod field.
48 size_t split = mod_or_key.find_first_of("/");
49 mod = mod_or_key.substr(0, split);
50 modmask = mod_or_key.substr(split + 1);
51 mod_or_key = static_cast<std::string>(t);
53 if(mod_or_key == "")
54 throw std::runtime_error("Expected optional modifiers and key");
55 keyname = mod_or_key;
56 command = t.tail();
57 if(command != "")
58 throw std::runtime_error("Unexpected argument");
59 keymapper::unbind(mod, modmask, keyname);
60 if(mod != "" || modmask != "")
61 messages << mod << "/" << modmask << " ";
62 messages << keyname << " unbound" << std::endl;
63 });
65 function_ptr_command<> show_bindings("show-bindings", "Show active bindings",
66 "Syntax: show-bindings\nShow bindings that are currently active.\n",
67 []() throw(std::bad_alloc, std::runtime_error) {
68 keymapper::dumpbindings();
69 });
72 std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc)
74 if(cmd == "")
75 return "";
76 if(cmd[0] != '+' && polarity)
77 return "";
78 if(cmd[0] == '+' && !polarity)
79 cmd[0] = '-';
80 return cmd;
83 namespace
85 std::map<std::string, modifier*>* known_modifiers;
86 std::map<std::string, std::string>* modifier_linkages;
87 std::map<std::string, keygroup*>* keygroups;
89 //Returns orig if not linked.
90 const modifier* get_linked_modifier(const modifier* orig)
92 if(!modifier_linkages || !modifier_linkages->count(orig->name()))
93 return orig;
94 std::string l = (*modifier_linkages)[orig->name()];
95 return (*known_modifiers)[l];
99 modifier::modifier(const std::string& name) throw(std::bad_alloc)
101 if(!known_modifiers)
102 known_modifiers = new std::map<std::string, modifier*>();
103 (*known_modifiers)[modname = name] = this;
106 modifier::modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc)
108 if(!known_modifiers)
109 known_modifiers = new std::map<std::string, modifier*>();
110 if(!modifier_linkages)
111 modifier_linkages = new std::map<std::string, std::string>();
112 (*known_modifiers)[modname = name] = this;
113 (*modifier_linkages)[name] = linkgroup;
116 modifier& modifier::lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error)
118 if(!known_modifiers || !known_modifiers->count(name)) {
119 std::ostringstream x;
120 x << "Invalid modifier '" << name << "'";
121 throw std::runtime_error(x.str());
123 return *(*known_modifiers)[name];
126 std::string modifier::name() const throw(std::bad_alloc)
128 return modname;
132 void modifier_set::add(const modifier& mod, bool really) throw(std::bad_alloc)
134 if(really)
135 set.insert(&mod);
138 void modifier_set::remove(const modifier& mod, bool really) throw(std::bad_alloc)
140 if(really)
141 set.erase(&mod);
144 modifier_set modifier_set::construct(const std::string& _modifiers) throw(std::bad_alloc, std::runtime_error)
146 modifier_set set;
147 std::string modifiers = _modifiers;
148 while(modifiers != "") {
149 std::string mod = modifiers;
150 std::string rest;
151 size_t split = modifiers.find_first_of(",");
152 if(split < modifiers.length()) {
153 mod = modifiers.substr(0, split);
154 rest = modifiers.substr(split + 1);
156 set.add(modifier::lookup(mod));
157 modifiers = rest;
159 return set;
162 bool modifier_set::valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc)
164 //No element can be together with its linkage group.
165 for(auto i = set.set.begin(); i != set.set.end(); ++i) {
166 const modifier* j = get_linked_modifier(*i);
167 if(*i != j && set.set.count(j))
168 return false;
170 for(auto i = mask.set.begin(); i != mask.set.end(); ++i) {
171 const modifier* j = get_linked_modifier(*i);
172 if(*i != j && mask.set.count(j))
173 return false;
175 //For every element of set, it or its linkage group must be in mask.
176 for(auto i = set.set.begin(); i != set.set.end(); ++i) {
177 const modifier* j = get_linked_modifier(*i);
178 if(!mask.set.count(*i) && !mask.set.count(j))
179 return false;
181 return true;
184 bool modifier_set::operator==(const modifier_set& m) const throw()
186 for(auto i = set.begin(); i != set.end(); ++i)
187 if(!m.set.count(*i))
188 return false;
189 for(auto i = m.set.begin(); i != m.set.end(); ++i)
190 if(!set.count(*i))
191 return false;
192 return true;
195 bool modifier_set::triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask)
196 throw(std::bad_alloc)
198 modifier_set unmet = trigger;
199 modifier_set blank;
200 for(auto i = set.set.begin(); i != set.set.end(); i++) {
201 auto linked = get_linked_modifier(*i);
202 if(mask.set.count(linked) && trigger.set.count(linked))
203 unmet.remove(*linked);
204 if(mask.set.count(linked) && trigger.set.count(*i))
205 unmet.remove(**i);
206 if(mask.set.count(*i) && trigger.set.count(*i))
207 unmet.remove(**i);
209 return (unmet == blank);
212 std::string keygroup::name() throw(std::bad_alloc)
214 return keyname;
218 keygroup::keygroup(const std::string& name, enum type t) throw(std::bad_alloc)
220 if(!keygroups)
221 keygroups = new std::map<std::string, keygroup*>();
222 (*keygroups)[keyname = name] = this;
223 ktype = t;
224 state = 0;
225 cal_left = -32768;
226 cal_center = 0;
227 cal_right = 32767;
228 cal_tolerance = 0.5;
231 void keygroup::change_type(enum type t)
233 ktype = t;
234 state = 0;
237 std::pair<keygroup*, unsigned> keygroup::lookup(const std::string& name) throw(std::bad_alloc,
238 std::runtime_error)
240 if(!keygroups)
241 throw std::runtime_error("Invalid key");
242 if(keygroups->count(name))
243 return std::make_pair((*keygroups)[name], 0);
244 std::string prefix = name;
245 char letter = prefix[prefix.length() - 1];
246 prefix = prefix.substr(0, prefix.length() - 1);
247 if(!keygroups->count(prefix))
248 throw std::runtime_error("Invalid key");
249 keygroup* g = (*keygroups)[prefix];
250 switch(letter) {
251 case '+':
252 case 'n':
253 return std::make_pair(g, 0);
254 case '-':
255 case 'e':
256 return std::make_pair(g, 1);
257 case 's':
258 return std::make_pair(g, 2);
259 case 'w':
260 return std::make_pair(g, 3);
261 default:
262 throw std::runtime_error("Invalid key");
266 void keygroup::change_calibration(short left, short center, short right, double tolerance)
268 cal_left = left;
269 cal_center = center;
270 cal_right = right;
271 cal_tolerance = tolerance;
274 double keygroup::compensate(short value)
276 if(ktype == KT_HAT || ktype == KT_KEY || ktype == KT_DISABLED)
277 return value; //These can't be calibrated.
278 if(value <= cal_left)
279 return -1.0;
280 else if(value >= cal_right)
281 return 1.0;
282 else if(value == cal_center)
283 return 0.0;
284 else if(value < cal_center)
285 return (static_cast<double>(value) - cal_center) / (static_cast<double>(cal_center) - cal_left);
286 else
287 return (static_cast<double>(value) - cal_center) / (static_cast<double>(cal_right) - cal_center);
290 double keygroup::compensate2(double value)
292 switch(ktype) {
293 case KT_DISABLED:
294 return 0; //Always neutral.
295 case KT_KEY:
296 case KT_HAT:
297 return value; //No mapping.
298 case KT_PRESSURE_0M:
299 return -value;
300 case KT_PRESSURE_0P:
301 return value;
302 case KT_PRESSURE_M0:
303 return 1 + value;
304 case KT_PRESSURE_MP:
305 return (1 + value) / 2;
306 case KT_PRESSURE_P0:
307 return 1 - value;
308 case KT_PRESSURE_PM:
309 return (1 - value) / 2;
310 case KT_AXIS_PAIR:
311 return value;
312 case KT_AXIS_PAIR_INVERSE:
313 return -value;
317 void keygroup::set_position(short pos, const modifier_set& modifiers) throw()
319 double x = compensate2(compensate(pos));
320 unsigned tmp;
321 bool left, right, up, down;
322 bool oleft, oright, oup, odown;
323 switch(ktype) {
324 case KT_DISABLED:
325 return;
326 case KT_KEY:
327 case KT_PRESSURE_0M:
328 case KT_PRESSURE_0P:
329 case KT_PRESSURE_M0:
330 case KT_PRESSURE_MP:
331 case KT_PRESSURE_P0:
332 case KT_PRESSURE_PM:
333 tmp = (x >= cal_tolerance);
334 run_listeners(modifiers, 0, true, (!state && tmp), x);
335 run_listeners(modifiers, 0, false, (state && !tmp), x);
336 state = tmp;
337 break;
338 case KT_AXIS_PAIR:
339 case KT_AXIS_PAIR_INVERSE:
340 if(x <= -cal_tolerance)
341 tmp = 2;
342 else if(x >= cal_tolerance)
343 tmp = 1;
344 else
345 tmp = 0;
346 run_listeners(modifiers, 0, false, state == 1 && tmp != 1, x);
347 run_listeners(modifiers, 1, false, state == 2 && tmp != 2, x);
348 run_listeners(modifiers, 0, true, tmp == 1 && state != 1, x);
349 run_listeners(modifiers, 1, true, tmp == 2 && state != 2, x);
350 state = tmp;
351 break;
352 case KT_HAT:
353 left = ((pos & 8) != 0);
354 right = ((pos & 2) != 0);
355 up = ((pos & 1) != 0);
356 down = ((pos & 4) != 0);
357 oleft = ((state & 8) != 0);
358 oright = ((state & 2) != 0);
359 oup = ((state & 1) != 0);
360 odown = ((state & 4) != 0);
361 run_listeners(modifiers, 3, false, oleft && !left, x);
362 run_listeners(modifiers, 1, false, oright && !right, x);
363 run_listeners(modifiers, 0, false, oup && !up, x);
364 run_listeners(modifiers, 2, false, odown && !down, x);
365 run_listeners(modifiers, 2, true, !odown && down, x);
366 run_listeners(modifiers, 0, true, !oup && up, x);
367 run_listeners(modifiers, 1, true, !oright && right, x);
368 run_listeners(modifiers, 3, true, !oleft && left, x);
369 state = pos;
370 break;
374 void keygroup::add_key_listener(key_listener& l) throw(std::bad_alloc)
376 listeners.push_back(&l);
379 void keygroup::remove_key_listener(key_listener& l) throw(std::bad_alloc)
381 for(auto i = listeners.begin(); i != listeners.end(); ++i)
382 if(*i == &l) {
383 listeners.erase(i);
384 return;
388 void keygroup::run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x)
390 if(!really)
391 return;
392 std::string name = keyname;
393 if(ktype == KT_AXIS_PAIR && subkey == 0)
394 name = name + "+";
395 if(ktype == KT_AXIS_PAIR && subkey == 1)
396 name = name + "-";
397 if(ktype == KT_HAT && subkey == 0)
398 name = name + "n";
399 if(ktype == KT_HAT && subkey == 1)
400 name = name + "e";
401 if(ktype == KT_HAT && subkey == 2)
402 name = name + "s";
403 if(ktype == KT_HAT && subkey == 3)
404 name = name + "w";
405 if(exclusive) {
406 exclusive->key_event(modifiers, *this, subkey, polarity, name);
407 return;
409 for(auto i = listeners.begin(); i != listeners.end(); ++i)
410 (*i)->key_event(modifiers, *this, subkey, polarity, name);
413 keygroup::key_listener* keygroup::exclusive;
415 void keygroup::set_exclusive_key_listener(key_listener* l) throw()
417 exclusive = l;
420 namespace
422 struct triple
424 triple(const std::string& _a, const std::string& _b, const std::string& _c)
426 a = _a;
427 b = _b;
428 c = _c;
430 std::string a;
431 std::string b;
432 std::string c;
433 bool operator==(const triple& t) const
435 bool x = (a == t.a && b == t.b && c == t.c);
436 return x;
438 bool operator<(const triple& t) const
440 bool x = (a < t.a || (a == t.a && b < t.b) || (a == t.a && b == t.b && c < t.c));
441 return x;
444 struct keybind_data : public keygroup::key_listener
446 modifier_set mod;
447 modifier_set modmask;
448 keygroup* group;
449 unsigned subkey;
450 std::string command;
451 void key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey, bool polarity,
452 const std::string& name)
454 if(!modifier_set::triggers(modifiers, mod, modmask))
455 return;
456 std::string cmd = fixup_command_polarity(command, polarity);
457 if(cmd == "")
458 return;
459 command::invokeC(cmd);
463 std::map<triple, keybind_data> keybindings;
466 void keymapper::bind(std::string mod, std::string modmask, std::string keyname, std::string command)
467 throw(std::bad_alloc, std::runtime_error)
469 triple k(mod, modmask, keyname);
470 modifier_set _mod = modifier_set::construct(mod);
471 modifier_set _modmask = modifier_set::construct(modmask);
472 if(!modifier_set::valid(_mod, _modmask))
473 throw std::runtime_error("Invalid modifiers");
474 auto g = keygroup::lookup(keyname);
475 if(!keybindings.count(k)) {
476 keybindings[k].mod = _mod;
477 keybindings[k].modmask = _modmask;
478 keybindings[k].group = g.first;
479 keybindings[k].subkey = g.second;
480 g.first->add_key_listener(keybindings[k]);
482 keybindings[k].command = command;
484 void keymapper::unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
485 std::runtime_error)
487 triple k(mod, modmask, keyname);
488 if(!keybindings.count(k))
489 throw std::runtime_error("Key is not bound");
490 keybindings[k].group->remove_key_listener(keybindings[k]);
491 keybindings.erase(k);
494 void keymapper::dumpbindings() throw(std::bad_alloc)
496 for(auto i = keybindings.begin(); i != keybindings.end(); ++i) {
497 messages << "bind-key ";
498 if(i->first.a != "" || i->first.b != "")
499 messages << i->first.a << "/" << i->first.b << " ";
500 messages << i->first.c << std::endl;