Allow specifying ROM type in file load dialog
[lsnes.git] / src / library / keyboard.cpp
blobfdcc99935b273406ed84868e08d5d7911e629b18
1 #include "keyboard.hpp"
2 #include <iostream>
4 void keyboard::do_register_modifier(const std::string& name, keyboard_modifier& mod) throw(std::bad_alloc)
6 umutex_class u(mutex);
7 modifiers[name] = &mod;
10 void keyboard::do_unregister_modifier(const std::string& name) throw()
12 umutex_class u(mutex);
13 modifiers.erase(name);
16 keyboard_modifier& keyboard::lookup_modifier(const std::string& name) throw(std::runtime_error)
18 keyboard_modifier* m = try_lookup_modifier(name);
19 if(!m)
20 throw std::runtime_error("No such modifier");
21 return *m;
24 keyboard_modifier* keyboard::try_lookup_modifier(const std::string& name) throw()
26 umutex_class u(mutex);
27 if(!modifiers.count(name))
28 return NULL;
29 return modifiers[name];
32 std::list<keyboard_modifier*> keyboard::all_modifiers() throw(std::bad_alloc)
34 umutex_class u(mutex);
35 std::list<keyboard_modifier*> r;
36 for(auto i : modifiers)
37 r.push_back(i.second);
38 return r;
41 void keyboard::do_register_key(const std::string& name, keyboard_key& key) throw(std::bad_alloc)
43 umutex_class u(mutex);
44 keys[name] = &key;
47 void keyboard::do_unregister_key(const std::string& name) throw()
49 umutex_class u(mutex);
50 keys.erase(name);
53 keyboard_key& keyboard::lookup_key(const std::string& name) throw(std::runtime_error)
55 keyboard_key* m = try_lookup_key(name);
56 if(!m)
57 throw std::runtime_error("No such key");
58 return *m;
61 keyboard_key* keyboard::try_lookup_key(const std::string& name) throw()
63 umutex_class u(mutex);
64 if(!keys.count(name))
65 return NULL;
66 return keys[name];
69 std::list<keyboard_key*> keyboard::all_keys() throw(std::bad_alloc)
71 umutex_class u(mutex);
72 std::list<keyboard_key*> r;
73 for(auto i : keys)
74 r.push_back(i.second);
75 return r;
78 void keyboard::set_exclusive(keyboard_event_listener* listener) throw()
80 umutex_class u(mutex);
81 for(auto i : keys)
82 i.second->set_exclusive(listener);
85 void keyboard::set_current_key(keyboard_key* key) throw()
87 umutex_class u(mutex);
88 current_key = key;
91 keyboard_key* keyboard::get_current_key() throw()
93 umutex_class u(mutex);
94 return current_key;
97 keyboard::keyboard() throw(std::bad_alloc)
98 : modifier_proxy(*this), key_proxy(*this)
100 register_queue<keyboard::_modifier_proxy, keyboard_modifier>::do_ready(modifier_proxy, true);
101 register_queue<keyboard::_key_proxy, keyboard_key>::do_ready(key_proxy, true);
104 keyboard::~keyboard() throw()
106 register_queue<keyboard::_modifier_proxy, keyboard_modifier>::do_ready(modifier_proxy, false);
107 register_queue<keyboard::_key_proxy, keyboard_key>::do_ready(key_proxy, false);
110 void keyboard_modifier_set::add(keyboard_modifier& mod, bool really) throw(std::bad_alloc)
112 if(really)
113 set.insert(&mod);
116 void keyboard_modifier_set::remove(keyboard_modifier& mod, bool really) throw(std::bad_alloc)
118 if(really)
119 set.erase(&mod);
122 keyboard_modifier_set keyboard_modifier_set::construct(keyboard& kbd, const std::string& _modifiers)
123 throw(std::bad_alloc, std::runtime_error)
125 keyboard_modifier_set set;
126 std::string modifiers = _modifiers;
127 while(modifiers != "") {
128 std::string mod = modifiers;
129 std::string rest;
130 size_t split = modifiers.find_first_of(",");
131 if(split < modifiers.length()) {
132 mod = modifiers.substr(0, split);
133 rest = modifiers.substr(split + 1);
135 set.add(kbd.lookup_modifier(mod));
136 modifiers = rest;
138 return set;
141 bool keyboard_modifier_set::valid(keyboard_modifier_set& mask) throw(std::bad_alloc)
143 //No element can be together with its linkage group.
144 for(auto i : set) {
145 keyboard_modifier* j = i->get_link();
146 if(j && set.count(j))
147 return false;
149 for(auto i : mask.set) {
150 keyboard_modifier* j = i->get_link();
151 if(j && mask.set.count(j))
152 return false;
154 //For every element of set, it or its linkage group must be in mask.
155 for(auto i : set) {
156 keyboard_modifier* j = i->get_link();
157 if(!mask.set.count(i) && !mask.set.count(j ? j : i))
158 return false;
160 return true;
163 bool keyboard_modifier_set::operator==(const keyboard_modifier_set& m) const throw()
165 for(auto i : set)
166 if(!m.set.count(i))
167 return false;
168 for(auto i : m.set)
169 if(!set.count(i))
170 return false;
171 return true;
174 bool keyboard_modifier_set::operator<(const keyboard_modifier_set& m) const throw()
176 auto i1 = set.begin();
177 auto i2 = m.set.begin();
178 for(; i1 != set.end() && i2 != m.set.end(); i1++, i2++) {
179 if((uint64_t)*i1 < (uint64_t)*i2)
180 return true;
181 if((uint64_t)*i1 > (uint64_t)*i2)
182 return false;
184 return (i2 != m.set.end());
187 keyboard_modifier_set::operator std::string() const throw(std::bad_alloc)
189 std::string r;
190 for(auto i : set)
191 r = r + ((r != "") ? "," : "") + i->get_name();
192 return r;
195 std::ostream& operator<<(std::ostream& os, const keyboard_modifier_set& m)
197 os << "<modset:";
198 for(auto i : m.set)
199 os << i->get_name() << " ";
200 os << ">";
201 return os;
204 bool keyboard_modifier_set::triggers(const keyboard_modifier_set& trigger, const keyboard_modifier_set& mask)
205 throw(std::bad_alloc)
207 for(auto i : mask.set) {
208 bool trigger_exact = trigger.set.count(i);
209 bool trigger_ingroup = false;
210 for(auto j : trigger.set)
211 if(j->get_link() == i)
212 trigger_ingroup = true;
213 bool trigger_none = !trigger_exact && !trigger_ingroup;
215 //If trigger_exact is set, then this key or a key in this group must be pressed.
216 if(trigger_exact) {
217 bool any = false;
218 for(auto j : set)
219 any = any || (j == i || j->get_link() == i);
220 if(!any)
221 return false;
223 //If trigger_ingroup is set, then exactly that set of keys in group must be pressed.
224 if(trigger_ingroup) {
225 for(auto j : i->get_keyboard().all_modifiers()) {
226 if(j->get_link() != i)
227 continue; //Not interested.
228 if((set.count(j) > 0) != (trigger.set.count(j) > 0))
229 return false;
232 //If trigger_none is set, then this key nor keys in this key group can't be pressed.
233 if(trigger_none) {
234 bool any = false;
235 for(auto j : set)
236 any = any || (j == i || j->get_link() == i);
237 if(any)
238 return false;
241 return true;
244 int32_t keyboard_axis_calibration::get_calibrated_value(int32_t x) const throw()
246 if(x < left)
247 return -32767;
248 if(x > right)
249 return 32767;
250 if(x == center)
251 return 0;
252 double width;
253 if(x < center)
254 width = center - (double)left;
255 else if(x > center)
256 width = (double)right - center;
257 return 32767.0 * (x - (double)center) / width;
260 int keyboard_axis_calibration::get_digital_state(int32_t x) const throw()
262 if(mode < 0)
263 return 0;
264 if(mode == 0) {
265 int m = (esign_a + 1) * 3 + esign_b + 1;
266 bool dwidth;
267 bool negative;
268 int32_t shift;
269 switch(m) {
270 case 0: case 4: case 8: break; //These are not legal.
271 case 1: dwidth = false; negative = false; shift=32767; break; //- to 0.
272 case 2: dwidth = true; negative = false; shift=32767; break; //- to +.
273 case 3: dwidth = false; negative = true; shift=0; break; //0 to -.
274 case 5: dwidth = false; negative = false; shift=0; break; //0 to +.
275 case 6: dwidth = true; negative = true; shift=32767; break; //+ to -.
276 case 7: dwidth = false; negative = true; shift=32767; break; //+ to 0.
278 if(negative)
279 x = -x;
280 x += shift;
281 int32_t threshold = (int32_t)((dwidth ? 65535 : 32767) * nullwidth);
282 return (x > threshold) ? 1 : 0;
284 if(mode == 1) {
285 int32_t tolerance = (int32_t)(32767 * nullwidth);
286 if(x < -tolerance)
287 return esign_a;
288 if(x > tolerance)
289 return esign_b;
290 return 0;
292 return 0;
295 int32_t keyboard_mouse_calibration::get_calibrated_value(int32_t x) const throw()
297 return x - offset;
300 keyboard_event::~keyboard_event() throw() {}
301 keyboard_event_key::~keyboard_event_key() throw() {}
302 keyboard_event_axis::~keyboard_event_axis() throw() {}
303 keyboard_event_hat::~keyboard_event_hat() throw() {}
304 keyboard_event_mouse::~keyboard_event_mouse() throw() {}
305 keyboard_event_listener::~keyboard_event_listener() throw() {}
307 keyboard_key::~keyboard_key() throw()
309 register_queue<keyboard::_key_proxy, keyboard_key>::do_unregister(kbd.key_proxy, name);
312 keyboard_event_key::keyboard_event_key(uint32_t chngmask)
313 : keyboard_event(chngmask, keyboard_keytype::KBD_KEYTYPE_KEY)
317 keyboard_event_axis::keyboard_event_axis(int32_t _state, uint32_t chngmask, const keyboard_axis_calibration& _cal)
318 : keyboard_event(chngmask, keyboard_keytype::KBD_KEYTYPE_AXIS)
320 state = _state;
321 cal = _cal;
324 keyboard_event_hat::keyboard_event_hat(uint32_t chngmask)
325 : keyboard_event(chngmask, keyboard_keytype::KBD_KEYTYPE_HAT)
329 keyboard_event_mouse::keyboard_event_mouse(int32_t _state, const keyboard_mouse_calibration& _cal)
330 : keyboard_event(0, keyboard_keytype::KBD_KEYTYPE_MOUSE)
332 state = _state;
333 cal = _cal;
336 int32_t keyboard_event_key::get_state() const throw() { return (get_change_mask() & 1) != 0; }
337 int32_t keyboard_event_axis::get_state() const throw() { return state; }
338 int32_t keyboard_event_mouse::get_state() const throw() { return state; }
340 int32_t keyboard_event_hat::get_state() const throw()
342 int32_t r = 0;
343 uint32_t m = get_change_mask();
344 if(m & 1) r |= 1;
345 if(m & 4) r |= 2;
346 if(m & 16) r |= 4;
347 if(m & 64) r |= 8;
348 return m;
351 keyboard_key::keyboard_key(keyboard& keyb, const std::string& _name, const std::string& _clazz,
352 keyboard_keytype _type) throw(std::bad_alloc)
353 : kbd(keyb), clazz(_clazz), name(_name), type(_type)
355 exclusive_listener = NULL;
356 register_queue<keyboard::_key_proxy, keyboard_key>::do_register(kbd.key_proxy, name, *this);
359 void keyboard_key::add_listener(keyboard_event_listener& listener, bool analog) throw(std::bad_alloc)
361 if(analog) {
362 analog_listeners.insert(&listener);
363 digital_listeners.erase(&listener);
364 } else {
365 digital_listeners.insert(&listener);
366 analog_listeners.erase(&listener);
369 void keyboard_key::remove_listener(keyboard_event_listener& listener) throw()
371 digital_listeners.erase(&listener);
372 analog_listeners.erase(&listener);
375 void keyboard_key::set_exclusive(keyboard_event_listener* listener) throw()
377 umutex_class u(mutex);
378 exclusive_listener = listener;
381 void keyboard_key::call_listeners(keyboard_modifier_set& mods, keyboard_event& event)
383 kbd.set_current_key(this);
384 bool digital = (event.get_change_mask() & 0xAAAAAAAAUL) != 0;
385 mutex.lock();
386 if(exclusive_listener) {
387 mutex.unlock();
388 exclusive_listener->on_key_event(mods, *this, event);
389 kbd.set_current_key(NULL);
390 return;
392 keyboard_event_listener* itr = NULL;
393 while(digital) {
394 auto itr2 = digital_listeners.upper_bound(itr);
395 if(itr2 == digital_listeners.end())
396 break;
397 itr = *itr2;
398 mutex.unlock();
399 itr->on_key_event(mods, *this, event);
400 mutex.lock();
402 itr = NULL;
403 while(true) {
404 auto itr2 = analog_listeners.upper_bound(itr);
405 if(itr2 == analog_listeners.end())
406 break;
407 itr = *itr2;
408 mutex.unlock();
409 itr->on_key_event(mods, *this, event);
410 mutex.lock();
412 mutex.unlock();
413 kbd.set_current_key(NULL);
416 keyboard_key_axis* keyboard_key::cast_axis() throw()
418 if(type != KBD_KEYTYPE_AXIS)
419 return NULL;
420 return dynamic_cast<keyboard_key_axis*>(this);
423 keyboard_key_mouse* keyboard_key::cast_mouse() throw()
425 if(type != KBD_KEYTYPE_MOUSE)
426 return NULL;
427 return dynamic_cast<keyboard_key_mouse*>(this);
430 keyboard_key_key::keyboard_key_key(keyboard& keyb, const std::string& name, const std::string& clazz)
431 throw(std::bad_alloc)
432 : keyboard_key(keyb, name, clazz, keyboard_keytype::KBD_KEYTYPE_KEY)
434 state = 0;
437 keyboard_key_key::~keyboard_key_key() throw() {}
439 void keyboard_key_key::set_state(keyboard_modifier_set mods, int32_t _state) throw()
441 uint32_t change = _state ? 1 : 0;
442 bool edge = false;
443 mutex.lock();
444 if(state != _state) {
445 state = _state;
446 change |= 2;
447 edge = true;
449 mutex.unlock();
450 if(edge) {
451 keyboard_event_key e(change);
452 call_listeners(mods, e);
456 int32_t keyboard_key_key::get_state() const throw() { return state; }
457 int32_t keyboard_key_key::get_state_digital() const throw() { return state; }
459 std::vector<std::string> keyboard_key_key::get_subkeys() throw(std::bad_alloc)
461 std::vector<std::string> r;
462 r.push_back("");
463 return r;
466 keyboard_key_hat::keyboard_key_hat(keyboard& keyb, const std::string& name, const std::string& clazz)
467 throw(std::bad_alloc)
468 : keyboard_key(keyb, name, clazz, keyboard_keytype::KBD_KEYTYPE_HAT)
470 state = 0;
472 keyboard_key_hat::~keyboard_key_hat() throw() {}
474 void keyboard_key_hat::set_state(keyboard_modifier_set mods, int32_t _state) throw()
476 state &= 15;
477 uint32_t change = 0;
478 bool edge = false;
479 mutex.lock();
480 if(state != _state) {
481 int32_t schange = state ^ _state;
482 state = _state;
483 if(state & 1) change |= 1;
484 if(schange & 1) change |= 2;
485 if(state & 2) change |= 4;
486 if(schange & 2) change |= 8;
487 if(state & 4) change |= 16;
488 if(schange & 4) change |= 32;
489 if(state & 8) change |= 64;
490 if(schange & 8) change |= 128;
491 edge = true;
493 mutex.unlock();
494 if(edge) {
495 keyboard_event_hat e(change);
496 call_listeners(mods, e);
500 int32_t keyboard_key_hat::get_state() const throw() { return state; }
501 int32_t keyboard_key_hat::get_state_digital() const throw() { return state; }
503 std::vector<std::string> keyboard_key_hat::get_subkeys() throw(std::bad_alloc)
505 std::vector<std::string> r;
506 r.push_back("n");
507 r.push_back("e");
508 r.push_back("s");
509 r.push_back("w");
510 return r;
513 keyboard_key_axis::keyboard_key_axis(keyboard& keyb, const std::string& name, const std::string& clazz,
514 keyboard_axis_calibration _cal) throw(std::bad_alloc)
515 : keyboard_key(keyb, name, clazz, keyboard_keytype::KBD_KEYTYPE_AXIS)
517 rawstate = 0;
518 cal = _cal;
520 keyboard_key_axis::~keyboard_key_axis() throw() {}
522 int32_t keyboard_key_axis::get_state() const throw()
524 umutex_class u(mutex);
525 return cal.get_calibrated_value(rawstate);
528 int32_t keyboard_key_axis::get_state_digital() const throw()
530 umutex_class u(mutex);
531 int32_t tmp = cal.get_calibrated_value(rawstate);
532 return cal.get_digital_state(tmp);
535 keyboard_axis_calibration keyboard_key_axis::get_calibration() const throw()
537 umutex_class u(mutex);
538 keyboard_axis_calibration tmp = cal;
539 return tmp;
542 std::vector<std::string> keyboard_key_axis::get_subkeys() throw(std::bad_alloc)
544 umutex_class u(mutex);
545 std::vector<std::string> r;
546 if(cal.mode == 0)
547 r.push_back("");
548 else if(cal.mode > 0) {
549 r.push_back("+");
550 r.push_back("-");
552 return r;
555 void keyboard_key_axis::set_state(keyboard_modifier_set mods, int32_t _rawstate) throw()
557 bool edge = false;
558 int32_t state, ostate;
559 uint32_t change = 0;
560 int dold = 0, dnew = 0;
561 keyboard_axis_calibration _cal;
562 mutex.lock();
563 if(rawstate != _rawstate) {
564 ostate = cal.get_calibrated_value(rawstate);
565 dold = cal.get_digital_state(ostate);
566 rawstate = _rawstate;
567 state = cal.get_calibrated_value(rawstate);
568 dnew = cal.get_digital_state(state);
569 if(dnew > 0)
570 change |= 1;
571 if((dold > 0 && dnew <= 0) || (dold <= 0 && dnew > 0))
572 change |= 2;
573 if(dnew < 0)
574 change |= 4;
575 if((dold < 0 && dnew >= 0) || (dold >= 0 && dnew < 0))
576 change |= 8;
577 _cal = cal;
578 edge = true;
580 mutex.unlock();
581 if(edge) {
582 keyboard_event_axis e(state, change, _cal);
583 call_listeners(mods, e);
587 void keyboard_key_axis::set_calibration(keyboard_axis_calibration _cal) throw()
589 uint32_t change = 0;
590 int dold = 0, dnew = 0;
591 mutex.lock();
592 int32_t ostate = cal.get_calibrated_value(rawstate);
593 dold = cal.get_digital_state(ostate);
594 cal = _cal;
595 int32_t state = cal.get_calibrated_value(rawstate);
596 dnew = cal.get_digital_state(state);
597 if(dnew < 0)
598 change |= 1;
599 if((dold < 0 && dnew >= 0) || (dold >= 0 && dnew < 0))
600 change |= 2;
601 if(dnew > 0)
602 change |= 4;
603 if((dold > 0 && dnew <= 0) || (dold <= 0 && dnew > 0))
604 change |= 8;
605 mutex.unlock();
606 keyboard_event_axis e(change, state, _cal);
607 keyboard_modifier_set mods;
608 call_listeners(mods, e);
611 keyboard_key_mouse::keyboard_key_mouse(keyboard& keyb, const std::string& name, const std::string& clazz,
612 keyboard_mouse_calibration _cal) throw(std::bad_alloc)
613 : keyboard_key(keyb, name, clazz, keyboard_keytype::KBD_KEYTYPE_MOUSE)
615 rawstate = 0;
616 cal = _cal;
619 keyboard_key_mouse::~keyboard_key_mouse() throw() {}
620 int32_t keyboard_key_mouse::get_state_digital() const throw() { return 0; }
622 int32_t keyboard_key_mouse::get_state() const throw()
624 umutex_class u(mutex);
625 return cal.get_calibrated_value(rawstate);
628 std::vector<std::string> keyboard_key_mouse::get_subkeys() throw(std::bad_alloc)
630 return std::vector<std::string>();
633 keyboard_mouse_calibration keyboard_key_mouse::get_calibration() const throw()
635 umutex_class u(mutex);
636 keyboard_mouse_calibration tmp = cal;
637 return tmp;
640 void keyboard_key_mouse::set_state(keyboard_modifier_set mods, int32_t _rawstate) throw()
642 bool edge = false;
643 int32_t state;
644 keyboard_mouse_calibration _cal;
645 mutex.lock();
646 if(rawstate != _rawstate) {
647 rawstate = _rawstate;
648 state = cal.get_calibrated_value(rawstate);
649 _cal = cal;
650 edge = true;
652 mutex.unlock();
653 if(edge) {
654 keyboard_event_mouse e(state, _cal);
655 call_listeners(mods, e);
659 void keyboard_key_mouse::set_calibration(keyboard_mouse_calibration _cal) throw()
661 mutex.lock();
662 cal = _cal;
663 int32_t state = cal.get_calibrated_value(rawstate);
664 mutex.unlock();
665 keyboard_event_mouse e(state, _cal);
666 keyboard_modifier_set mods;
667 call_listeners(mods, e);