bsnes: redump sprite/palette functions
[lsnes.git] / src / library / keyboard.cpp
blobef1204e13816f5290b3789fda414c6edab7dfdcf
1 #include "keyboard.hpp"
2 #include <iostream>
4 namespace keyboard
6 void keyboard::do_register_modifier(const std::string& name, modifier& mod) throw(std::bad_alloc)
8 umutex_class u(mutex);
9 modifiers[name] = &mod;
12 void keyboard::do_unregister_modifier(const std::string& name) throw()
14 umutex_class u(mutex);
15 modifiers.erase(name);
18 modifier& keyboard::lookup_modifier(const std::string& name) throw(std::runtime_error)
20 modifier* m = try_lookup_modifier(name);
21 if(!m)
22 throw std::runtime_error("No such modifier");
23 return *m;
26 modifier* keyboard::try_lookup_modifier(const std::string& name) throw()
28 umutex_class u(mutex);
29 if(!modifiers.count(name))
30 return NULL;
31 return modifiers[name];
34 std::list<modifier*> keyboard::all_modifiers() throw(std::bad_alloc)
36 umutex_class u(mutex);
37 std::list<modifier*> r;
38 for(auto i : modifiers)
39 r.push_back(i.second);
40 return r;
43 void keyboard::do_register_key(const std::string& name, key& key) throw(std::bad_alloc)
45 umutex_class u(mutex);
46 keys[name] = &key;
49 void keyboard::do_unregister_key(const std::string& name) throw()
51 umutex_class u(mutex);
52 keys.erase(name);
55 key& keyboard::lookup_key(const std::string& name) throw(std::runtime_error)
57 key* m = try_lookup_key(name);
58 if(!m)
59 throw std::runtime_error("No such key");
60 return *m;
63 key* keyboard::try_lookup_key(const std::string& name) throw()
65 umutex_class u(mutex);
66 if(!keys.count(name))
67 return NULL;
68 return keys[name];
71 std::list<key*> keyboard::all_keys() throw(std::bad_alloc)
73 umutex_class u(mutex);
74 std::list<key*> r;
75 for(auto i : keys)
76 r.push_back(i.second);
77 return r;
80 void keyboard::set_exclusive(event_listener* listener) throw()
82 umutex_class u(mutex);
83 for(auto i : keys)
84 i.second->set_exclusive(listener);
87 void keyboard::set_current_key(key* key) throw()
89 umutex_class u(mutex);
90 current_key = key;
93 key* keyboard::get_current_key() throw()
95 umutex_class u(mutex);
96 return current_key;
99 keyboard::keyboard() throw(std::bad_alloc)
100 : modifier_proxy(*this), key_proxy(*this)
102 register_queue<keyboard::_modifier_proxy, modifier>::do_ready(modifier_proxy, true);
103 register_queue<keyboard::_key_proxy, key>::do_ready(key_proxy, true);
106 keyboard::~keyboard() throw()
108 register_queue<keyboard::_modifier_proxy, modifier>::do_ready(modifier_proxy, false);
109 register_queue<keyboard::_key_proxy, key>::do_ready(key_proxy, false);
112 void modifier_set::add(modifier& mod, bool really) throw(std::bad_alloc)
114 if(really)
115 set.insert(&mod);
118 void modifier_set::remove(modifier& mod, bool really) throw(std::bad_alloc)
120 if(really)
121 set.erase(&mod);
124 modifier_set modifier_set::construct(keyboard& kbd, const std::string& _modifiers)
125 throw(std::bad_alloc, std::runtime_error)
127 modifier_set set;
128 std::string modifiers = _modifiers;
129 while(modifiers != "") {
130 std::string mod = modifiers;
131 std::string rest;
132 size_t split = modifiers.find_first_of(",");
133 if(split < modifiers.length()) {
134 mod = modifiers.substr(0, split);
135 rest = modifiers.substr(split + 1);
137 set.add(kbd.lookup_modifier(mod));
138 modifiers = rest;
140 return set;
143 bool modifier_set::valid(modifier_set& mask) throw(std::bad_alloc)
145 //No element can be together with its linkage group.
146 for(auto i : set) {
147 modifier* j = i->get_link();
148 if(j && set.count(j))
149 return false;
151 for(auto i : mask.set) {
152 modifier* j = i->get_link();
153 if(j && mask.set.count(j))
154 return false;
156 //For every element of set, it or its linkage group must be in mask.
157 for(auto i : set) {
158 modifier* j = i->get_link();
159 if(!mask.set.count(i) && !mask.set.count(j ? j : i))
160 return false;
162 return true;
165 bool modifier_set::operator==(const modifier_set& m) const throw()
167 for(auto i : set)
168 if(!m.set.count(i))
169 return false;
170 for(auto i : m.set)
171 if(!set.count(i))
172 return false;
173 return true;
176 bool modifier_set::operator<(const modifier_set& m) const throw()
178 auto i1 = set.begin();
179 auto i2 = m.set.begin();
180 for(; i1 != set.end() && i2 != m.set.end(); i1++, i2++) {
181 if((uint64_t)*i1 < (uint64_t)*i2)
182 return true;
183 if((uint64_t)*i1 > (uint64_t)*i2)
184 return false;
186 return (i2 != m.set.end());
189 modifier_set::operator std::string() const throw(std::bad_alloc)
191 std::string r;
192 for(auto i : set)
193 r = r + ((r != "") ? "," : "") + i->get_name();
194 return r;
197 std::ostream& operator<<(std::ostream& os, const modifier_set& m)
199 os << "<modset:";
200 for(auto i : m.set)
201 os << i->get_name() << " ";
202 os << ">";
203 return os;
206 bool modifier_set::triggers(const modifier_set& trigger, const modifier_set& mask)
207 throw(std::bad_alloc)
209 for(auto i : mask.set) {
210 bool trigger_exact = trigger.set.count(i);
211 bool trigger_ingroup = false;
212 for(auto j : trigger.set)
213 if(j->get_link() == i)
214 trigger_ingroup = true;
215 bool trigger_none = !trigger_exact && !trigger_ingroup;
217 //If trigger_exact is set, then this key or a key in this group must be pressed.
218 if(trigger_exact) {
219 bool any = false;
220 for(auto j : set)
221 any = any || (j == i || j->get_link() == i);
222 if(!any)
223 return false;
225 //If trigger_ingroup is set, then exactly that set of keys in group must be pressed.
226 if(trigger_ingroup) {
227 for(auto j : i->get_keyboard().all_modifiers()) {
228 if(j->get_link() != i)
229 continue; //Not interested.
230 if((set.count(j) > 0) != (trigger.set.count(j) > 0))
231 return false;
234 //If trigger_none is set, then this key nor keys in this key group can't be pressed.
235 if(trigger_none) {
236 bool any = false;
237 for(auto j : set)
238 any = any || (j == i || j->get_link() == i);
239 if(any)
240 return false;
243 return true;
246 int32_t mouse_calibration::get_calibrated_value(int32_t x) const throw()
248 return x - offset;
251 event::~event() throw() {}
252 event_key::~event_key() throw() {}
253 event_axis::~event_axis() throw() {}
254 event_hat::~event_hat() throw() {}
255 event_mouse::~event_mouse() throw() {}
256 event_listener::~event_listener() throw() {}
258 key::~key() throw()
260 register_queue<keyboard::_key_proxy, key>::do_unregister(kbd.key_proxy, name);
263 event_key::event_key(uint32_t chngmask)
264 : event(chngmask, keytype::KBD_KEYTYPE_KEY)
268 event_axis::event_axis(int32_t _state, uint32_t chngmask)
269 : event(chngmask, keytype::KBD_KEYTYPE_AXIS)
271 state = _state;
274 event_hat::event_hat(uint32_t chngmask)
275 : event(chngmask, keytype::KBD_KEYTYPE_HAT)
279 event_mouse::event_mouse(int32_t _state, const mouse_calibration& _cal)
280 : event(0, keytype::KBD_KEYTYPE_MOUSE)
282 state = _state;
283 cal = _cal;
286 int32_t event_key::get_state() const throw() { return (get_change_mask() & 1) != 0; }
287 int32_t event_axis::get_state() const throw() { return state; }
288 int32_t event_mouse::get_state() const throw() { return state; }
290 int32_t event_hat::get_state() const throw()
292 int32_t r = 0;
293 uint32_t m = get_change_mask();
294 if(m & 1) r |= 1;
295 if(m & 4) r |= 2;
296 if(m & 16) r |= 4;
297 if(m & 64) r |= 8;
298 return m;
301 key::key(keyboard& keyb, const std::string& _name, const std::string& _clazz,
302 keytype _type) throw(std::bad_alloc)
303 : kbd(keyb), clazz(_clazz), name(_name), type(_type)
305 exclusive_listener = NULL;
306 register_queue<keyboard::_key_proxy, key>::do_register(kbd.key_proxy, name, *this);
309 void key::add_listener(event_listener& listener, bool analog) throw(std::bad_alloc)
311 if(analog) {
312 analog_listeners.insert(&listener);
313 digital_listeners.erase(&listener);
314 } else {
315 digital_listeners.insert(&listener);
316 analog_listeners.erase(&listener);
319 void key::remove_listener(event_listener& listener) throw()
321 digital_listeners.erase(&listener);
322 analog_listeners.erase(&listener);
325 void key::set_exclusive(event_listener* listener) throw()
327 umutex_class u(mutex);
328 exclusive_listener = listener;
331 void key::call_listeners(modifier_set& mods, event& event)
333 kbd.set_current_key(this);
334 bool digital = (event.get_change_mask() & 0xAAAAAAAAUL) != 0;
335 mutex.lock();
336 if(exclusive_listener) {
337 mutex.unlock();
338 exclusive_listener->on_key_event(mods, *this, event);
339 kbd.set_current_key(NULL);
340 return;
342 event_listener* itr = NULL;
343 while(digital) {
344 auto itr2 = digital_listeners.upper_bound(itr);
345 if(itr2 == digital_listeners.end())
346 break;
347 itr = *itr2;
348 mutex.unlock();
349 itr->on_key_event(mods, *this, event);
350 mutex.lock();
352 itr = NULL;
353 while(true) {
354 auto itr2 = analog_listeners.upper_bound(itr);
355 if(itr2 == analog_listeners.end())
356 break;
357 itr = *itr2;
358 mutex.unlock();
359 itr->on_key_event(mods, *this, event);
360 mutex.lock();
362 mutex.unlock();
363 kbd.set_current_key(NULL);
366 key_axis* key::cast_axis() throw()
368 if(type != KBD_KEYTYPE_AXIS)
369 return NULL;
370 return dynamic_cast<key_axis*>(this);
373 key_mouse* key::cast_mouse() throw()
375 if(type != KBD_KEYTYPE_MOUSE)
376 return NULL;
377 return dynamic_cast<key_mouse*>(this);
380 key_key::key_key(keyboard& keyb, const std::string& name, const std::string& clazz)
381 throw(std::bad_alloc)
382 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_KEY)
384 state = 0;
387 key_key::~key_key() throw() {}
389 void key_key::set_state(modifier_set mods, int32_t _state) throw()
391 uint32_t change = _state ? 1 : 0;
392 bool edge = false;
393 mutex.lock();
394 if(state != _state) {
395 state = _state;
396 change |= 2;
397 edge = true;
399 mutex.unlock();
400 if(edge) {
401 event_key e(change);
402 call_listeners(mods, e);
406 int32_t key_key::get_state() const throw() { return state; }
407 int32_t key_key::get_state_digital() const throw() { return state; }
409 std::vector<std::string> key_key::get_subkeys() throw(std::bad_alloc)
411 std::vector<std::string> r;
412 r.push_back("");
413 return r;
416 key_hat::key_hat(keyboard& keyb, const std::string& name, const std::string& clazz)
417 throw(std::bad_alloc)
418 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_HAT)
420 state = 0;
422 key_hat::~key_hat() throw() {}
424 void key_hat::set_state(modifier_set mods, int32_t _state) throw()
426 state &= 15;
427 uint32_t change = 0;
428 bool edge = false;
429 mutex.lock();
430 if(state != _state) {
431 int32_t schange = state ^ _state;
432 state = _state;
433 if(state & 1) change |= 1;
434 if(schange & 1) change |= 2;
435 if(state & 2) change |= 4;
436 if(schange & 2) change |= 8;
437 if(state & 4) change |= 16;
438 if(schange & 4) change |= 32;
439 if(state & 8) change |= 64;
440 if(schange & 8) change |= 128;
441 edge = true;
443 mutex.unlock();
444 if(edge) {
445 event_hat e(change);
446 call_listeners(mods, e);
450 int32_t key_hat::get_state() const throw() { return state; }
451 int32_t key_hat::get_state_digital() const throw() { return state; }
453 std::vector<std::string> key_hat::get_subkeys() throw(std::bad_alloc)
455 std::vector<std::string> r;
456 r.push_back("n");
457 r.push_back("e");
458 r.push_back("s");
459 r.push_back("w");
460 return r;
463 key_axis::key_axis(keyboard& keyb, const std::string& name, const std::string& clazz,
464 int mode) throw(std::bad_alloc)
465 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_AXIS)
467 rawstate = 0;
468 digitalstate = 0;
469 last_tolerance = 0.5;
470 _mode = mode;
472 key_axis::~key_axis() throw() {}
474 int32_t key_axis::get_state() const throw()
476 umutex_class u(mutex);
477 return rawstate;
480 int32_t key_axis::get_state_digital() const throw()
482 umutex_class u(mutex);
483 if(rawstate <= -32768 * last_tolerance)
484 return -1;
485 if(rawstate >= 32767 * last_tolerance)
486 return 1;
487 return 0;
490 int key_axis::get_mode() const throw()
492 umutex_class u(mutex);
493 return _mode;
496 std::vector<std::string> key_axis::get_subkeys() throw(std::bad_alloc)
498 umutex_class u(mutex);
499 std::vector<std::string> r;
500 if(_mode == 0)
501 r.push_back("");
502 else if(_mode > 0) {
503 r.push_back("+");
504 r.push_back("-");
506 return r;
509 void key_axis::set_state(modifier_set mods, int32_t _rawstate) throw()
511 bool edge = false;
512 int32_t state, ostate;
513 uint32_t change = 0;
514 int dold = 0, dnew = 0;
515 mutex.lock();
516 if(rawstate != _rawstate) {
517 ostate = rawstate;
518 dold = digitalstate;
519 rawstate = _rawstate;
520 state = rawstate;
521 if(state <= -32768 * last_tolerance)
522 dnew = -1;
523 if(state >= 32767 * last_tolerance)
524 dnew = 1;
525 digitalstate = dnew;
526 if(dnew > 0)
527 change |= 1;
528 if((dold > 0 && dnew <= 0) || (dold <= 0 && dnew > 0))
529 change |= 2;
530 if(dnew < 0)
531 change |= 4;
532 if((dold < 0 && dnew >= 0) || (dold >= 0 && dnew < 0))
533 change |= 8;
534 edge = true;
536 mutex.unlock();
537 if(edge) {
538 event_axis e(state, change);
539 call_listeners(mods, e);
543 void key_axis::set_mode(int mode, double tolerance) throw()
545 umutex_class u(mutex);
546 _mode = mode;
547 last_tolerance = tolerance;
550 key_mouse::key_mouse(keyboard& keyb, const std::string& name, const std::string& clazz,
551 mouse_calibration _cal) throw(std::bad_alloc)
552 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_MOUSE)
554 rawstate = 0;
555 cal = _cal;
558 key_mouse::~key_mouse() throw() {}
559 int32_t key_mouse::get_state_digital() const throw() { return 0; }
561 int32_t key_mouse::get_state() const throw()
563 umutex_class u(mutex);
564 return cal.get_calibrated_value(rawstate);
567 std::vector<std::string> key_mouse::get_subkeys() throw(std::bad_alloc)
569 return std::vector<std::string>();
572 mouse_calibration key_mouse::get_calibration() const throw()
574 umutex_class u(mutex);
575 mouse_calibration tmp = cal;
576 return tmp;
579 void key_mouse::set_state(modifier_set mods, int32_t _rawstate) throw()
581 bool edge = false;
582 int32_t state;
583 mouse_calibration _cal;
584 mutex.lock();
585 if(rawstate != _rawstate) {
586 rawstate = _rawstate;
587 state = cal.get_calibrated_value(rawstate);
588 _cal = cal;
589 edge = true;
591 mutex.unlock();
592 if(edge) {
593 event_mouse e(state, _cal);
594 call_listeners(mods, e);
598 void key_mouse::set_calibration(mouse_calibration _cal) throw()
600 mutex.lock();
601 cal = _cal;
602 int32_t state = cal.get_calibrated_value(rawstate);
603 mutex.unlock();
604 event_mouse e(state, _cal);
605 modifier_set mods;
606 call_listeners(mods, e);