lsnes rr2-β24
[lsnes.git] / src / library / keyboard.cpp
blobd1fea188a57714d1d9ea6079450201918cec9b94
1 #include "keyboard.hpp"
2 #include "stateobject.hpp"
3 #include "threads.hpp"
4 #include <iostream>
6 namespace keyboard
8 namespace {
9 threads::rlock* global_lock;
10 threads::rlock& get_keyboard_lock()
12 if(!global_lock) global_lock = new threads::rlock;
13 return *global_lock;
16 struct keyboard_internal
18 std::map<std::string, modifier*> modifiers;
19 std::map<std::string, key*> keys;
21 typedef stateobject::type<keyboard, keyboard_internal> keyboard_internal_t;
24 void keyboard::do_register(const std::string& name, modifier& mod) throw(std::bad_alloc)
26 threads::arlock u(get_keyboard_lock());
27 auto& state = keyboard_internal_t::get(this);
28 if(state.modifiers.count(name)) return;
29 state.modifiers[name] = &mod;
32 void keyboard::do_unregister(const std::string& name, modifier& mod) throw()
34 threads::arlock u(get_keyboard_lock());
35 auto state = keyboard_internal_t::get_soft(this);
36 if(!state || !state->modifiers.count(name) || state->modifiers[name] != &mod) return;
37 state->modifiers.erase(name);
40 modifier& keyboard::lookup_modifier(const std::string& name) throw(std::runtime_error)
42 modifier* m = try_lookup_modifier(name);
43 if(!m)
44 throw std::runtime_error("No such modifier");
45 return *m;
48 modifier* keyboard::try_lookup_modifier(const std::string& name) throw()
50 threads::arlock u(get_keyboard_lock());
51 auto state = keyboard_internal_t::get_soft(this);
52 if(!state || !state->modifiers.count(name))
53 return NULL;
54 return state->modifiers[name];
57 std::list<modifier*> keyboard::all_modifiers() throw(std::bad_alloc)
59 threads::arlock u(get_keyboard_lock());
60 auto state = keyboard_internal_t::get_soft(this);
61 std::list<modifier*> r;
62 if(state)
63 for(auto i : state->modifiers)
64 r.push_back(i.second);
65 return r;
68 void keyboard::do_register(const std::string& name, key& key) throw(std::bad_alloc)
70 threads::arlock u(get_keyboard_lock());
71 auto& state = keyboard_internal_t::get(this);
72 if(state.keys.count(name)) return;
73 state.keys[name] = &key;
76 void keyboard::do_unregister(const std::string& name, key& key) throw()
78 threads::arlock u(get_keyboard_lock());
79 auto state = keyboard_internal_t::get_soft(this);
80 if(!state || !state->keys.count(name) || state->keys[name] != &key) return;
81 state->keys.erase(name);
84 key& keyboard::lookup_key(const std::string& name) throw(std::runtime_error)
86 key* m = try_lookup_key(name);
87 if(!m)
88 throw std::runtime_error("No such key");
89 return *m;
92 key* keyboard::try_lookup_key(const std::string& name) throw()
94 threads::arlock u(get_keyboard_lock());
95 auto state = keyboard_internal_t::get_soft(this);
96 if(!state || !state->keys.count(name))
97 return NULL;
98 return state->keys[name];
101 std::list<key*> keyboard::all_keys() throw(std::bad_alloc)
103 threads::arlock u(get_keyboard_lock());
104 auto state = keyboard_internal_t::get_soft(this);
105 std::list<key*> r;
106 if(state)
107 for(auto i : state->keys)
108 r.push_back(i.second);
109 return r;
112 void keyboard::set_exclusive(event_listener* listener) throw()
114 threads::arlock u(get_keyboard_lock());
115 auto state = keyboard_internal_t::get_soft(this);
116 if(state)
117 for(auto i : state->keys)
118 i.second->set_exclusive(listener);
121 void keyboard::set_current_key(key* key) throw()
123 threads::arlock u(get_keyboard_lock());
124 current_key = key;
127 key* keyboard::get_current_key() throw()
129 threads::arlock u(get_keyboard_lock());
130 return current_key;
133 keyboard::keyboard() throw(std::bad_alloc)
137 keyboard::~keyboard() throw()
139 threads::arlock u(get_keyboard_lock());
140 auto state = keyboard_internal_t::get_soft(this);
141 if(!state) return;
142 keyboard_internal_t::clear(this);
145 void modifier_set::add(modifier& mod, bool really) throw(std::bad_alloc)
147 if(really)
148 set.insert(&mod);
151 void modifier_set::remove(modifier& mod, bool really) throw(std::bad_alloc)
153 if(really)
154 set.erase(&mod);
157 modifier_set modifier_set::construct(keyboard& kbd, const std::string& _modifiers)
158 throw(std::bad_alloc, std::runtime_error)
160 modifier_set set;
161 std::string modifiers = _modifiers;
162 while(modifiers != "") {
163 std::string mod = modifiers;
164 std::string rest;
165 size_t split = modifiers.find_first_of(",");
166 if(split < modifiers.length()) {
167 mod = modifiers.substr(0, split);
168 rest = modifiers.substr(split + 1);
170 set.add(kbd.lookup_modifier(mod));
171 modifiers = rest;
173 return set;
176 bool modifier_set::valid(modifier_set& mask) throw(std::bad_alloc)
178 //No element can be together with its linkage group.
179 for(auto i : set) {
180 modifier* j = i->get_link();
181 if(j && set.count(j))
182 return false;
184 for(auto i : mask.set) {
185 modifier* j = i->get_link();
186 if(j && mask.set.count(j))
187 return false;
189 //For every element of set, it or its linkage group must be in mask.
190 for(auto i : set) {
191 modifier* j = i->get_link();
192 if(!mask.set.count(i) && !mask.set.count(j ? j : i))
193 return false;
195 return true;
198 bool modifier_set::operator==(const modifier_set& m) const throw()
200 for(auto i : set)
201 if(!m.set.count(i))
202 return false;
203 for(auto i : m.set)
204 if(!set.count(i))
205 return false;
206 return true;
209 bool modifier_set::operator<(const modifier_set& m) const throw()
211 auto i1 = set.begin();
212 auto i2 = m.set.begin();
213 for(; i1 != set.end() && i2 != m.set.end(); i1++, i2++) {
214 if((uint64_t)*i1 < (uint64_t)*i2)
215 return true;
216 if((uint64_t)*i1 > (uint64_t)*i2)
217 return false;
219 return (i2 != m.set.end());
222 modifier_set::operator std::string() const throw(std::bad_alloc)
224 std::string r;
225 for(auto i : set)
226 r = r + ((r != "") ? "," : "") + i->get_name();
227 return r;
230 std::ostream& operator<<(std::ostream& os, const modifier_set& m)
232 os << "<modset:";
233 for(auto i : m.set)
234 os << i->get_name() << " ";
235 os << ">";
236 return os;
239 bool modifier_set::triggers(const modifier_set& trigger, const modifier_set& mask)
240 throw(std::bad_alloc)
242 for(auto i : mask.set) {
243 bool trigger_exact = trigger.set.count(i);
244 bool trigger_ingroup = false;
245 for(auto j : trigger.set)
246 if(j->get_link() == i)
247 trigger_ingroup = true;
248 bool trigger_none = !trigger_exact && !trigger_ingroup;
250 //If trigger_exact is set, then this key or a key in this group must be pressed.
251 if(trigger_exact) {
252 bool any = false;
253 for(auto j : set)
254 any = any || (j == i || j->get_link() == i);
255 if(!any)
256 return false;
258 //If trigger_ingroup is set, then exactly that set of keys in group must be pressed.
259 if(trigger_ingroup) {
260 for(auto j : i->get_keyboard().all_modifiers()) {
261 if(j->get_link() != i)
262 continue; //Not interested.
263 if((set.count(j) > 0) != (trigger.set.count(j) > 0))
264 return false;
267 //If trigger_none is set, then this key nor keys in this key group can't be pressed.
268 if(trigger_none) {
269 bool any = false;
270 for(auto j : set)
271 any = any || (j == i || j->get_link() == i);
272 if(any)
273 return false;
276 return true;
279 int32_t mouse_calibration::get_calibrated_value(int32_t x) const throw()
281 return x - offset;
284 event::~event() throw() {}
285 event_key::~event_key() throw() {}
286 event_axis::~event_axis() throw() {}
287 event_hat::~event_hat() throw() {}
288 event_mouse::~event_mouse() throw() {}
289 event_listener::~event_listener() throw() {}
291 key::~key() throw()
293 kbd.do_unregister(name, *this);
296 event_key::event_key(uint32_t chngmask)
297 : event(chngmask, keytype::KBD_KEYTYPE_KEY)
301 event_axis::event_axis(int32_t _state, uint32_t chngmask)
302 : event(chngmask, keytype::KBD_KEYTYPE_AXIS)
304 state = _state;
307 event_hat::event_hat(uint32_t chngmask)
308 : event(chngmask, keytype::KBD_KEYTYPE_HAT)
312 event_mouse::event_mouse(int32_t _state, const mouse_calibration& _cal)
313 : event(0, keytype::KBD_KEYTYPE_MOUSE)
315 state = _state;
316 cal = _cal;
319 int32_t event_key::get_state() const throw() { return (get_change_mask() & 1) != 0; }
320 int32_t event_axis::get_state() const throw() { return state; }
321 int32_t event_mouse::get_state() const throw() { return state; }
323 int32_t event_hat::get_state() const throw()
325 int32_t r = 0;
326 uint32_t m = get_change_mask();
327 if(m & 1) r |= 1;
328 if(m & 4) r |= 2;
329 if(m & 16) r |= 4;
330 if(m & 64) r |= 8;
331 return m;
334 key::key(keyboard& keyb, const std::string& _name, const std::string& _clazz,
335 keytype _type) throw(std::bad_alloc)
336 : kbd(keyb), clazz(_clazz), name(_name), type(_type)
338 exclusive_listener = NULL;
339 kbd.do_register(name, *this);
342 void key::add_listener(event_listener& listener, bool analog) throw(std::bad_alloc)
344 if(analog) {
345 analog_listeners.insert(&listener);
346 digital_listeners.erase(&listener);
347 } else {
348 digital_listeners.insert(&listener);
349 analog_listeners.erase(&listener);
352 void key::remove_listener(event_listener& listener) throw()
354 digital_listeners.erase(&listener);
355 analog_listeners.erase(&listener);
358 void key::set_exclusive(event_listener* listener) throw()
360 threads::arlock u(get_keyboard_lock());
361 exclusive_listener = listener;
364 void key::call_listeners(modifier_set& mods, event& event)
366 kbd.set_current_key(this);
367 bool digital = (event.get_change_mask() & 0xAAAAAAAAUL) != 0;
368 get_keyboard_lock().lock();
369 if(exclusive_listener) {
370 get_keyboard_lock().unlock();
371 exclusive_listener->on_key_event(mods, *this, event);
372 kbd.set_current_key(NULL);
373 return;
375 event_listener* itr = NULL;
376 while(digital) {
377 auto itr2 = digital_listeners.upper_bound(itr);
378 if(itr2 == digital_listeners.end())
379 break;
380 itr = *itr2;
381 get_keyboard_lock().unlock();
382 itr->on_key_event(mods, *this, event);
383 get_keyboard_lock().lock();
385 itr = NULL;
386 while(true) {
387 auto itr2 = analog_listeners.upper_bound(itr);
388 if(itr2 == analog_listeners.end())
389 break;
390 itr = *itr2;
391 get_keyboard_lock().unlock();
392 itr->on_key_event(mods, *this, event);
393 get_keyboard_lock().lock();
395 get_keyboard_lock().unlock();
396 kbd.set_current_key(NULL);
399 key_axis* key::cast_axis() throw()
401 if(type != KBD_KEYTYPE_AXIS)
402 return NULL;
403 return dynamic_cast<key_axis*>(this);
406 key_mouse* key::cast_mouse() throw()
408 if(type != KBD_KEYTYPE_MOUSE)
409 return NULL;
410 return dynamic_cast<key_mouse*>(this);
413 key_key::key_key(keyboard& keyb, const std::string& name, const std::string& clazz)
414 throw(std::bad_alloc)
415 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_KEY)
417 state = 0;
420 key_key::~key_key() throw() {}
422 void key_key::set_state(modifier_set mods, int32_t _state) throw()
424 uint32_t change = _state ? 1 : 0;
425 bool edge = false;
426 get_keyboard_lock().lock();
427 if(state != _state) {
428 state = _state;
429 change |= 2;
430 edge = true;
432 get_keyboard_lock().unlock();
433 if(edge) {
434 event_key e(change);
435 call_listeners(mods, e);
439 int32_t key_key::get_state() const throw() { return state; }
440 int32_t key_key::get_state_digital() const throw() { return state; }
442 std::vector<std::string> key_key::get_subkeys() throw(std::bad_alloc)
444 std::vector<std::string> r;
445 r.push_back("");
446 return r;
449 key_hat::key_hat(keyboard& keyb, const std::string& name, const std::string& clazz)
450 throw(std::bad_alloc)
451 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_HAT)
453 state = 0;
455 key_hat::~key_hat() throw() {}
457 void key_hat::set_state(modifier_set mods, int32_t _state) throw()
459 state &= 15;
460 uint32_t change = 0;
461 bool edge = false;
462 get_keyboard_lock().lock();
463 if(state != _state) {
464 int32_t schange = state ^ _state;
465 state = _state;
466 if(state & 1) change |= 1;
467 if(schange & 1) change |= 2;
468 if(state & 2) change |= 4;
469 if(schange & 2) change |= 8;
470 if(state & 4) change |= 16;
471 if(schange & 4) change |= 32;
472 if(state & 8) change |= 64;
473 if(schange & 8) change |= 128;
474 edge = true;
476 get_keyboard_lock().unlock();
477 if(edge) {
478 event_hat e(change);
479 call_listeners(mods, e);
483 int32_t key_hat::get_state() const throw() { return state; }
484 int32_t key_hat::get_state_digital() const throw() { return state; }
486 std::vector<std::string> key_hat::get_subkeys() throw(std::bad_alloc)
488 std::vector<std::string> r;
489 r.push_back("n");
490 r.push_back("e");
491 r.push_back("s");
492 r.push_back("w");
493 return r;
496 key_axis::key_axis(keyboard& keyb, const std::string& name, const std::string& clazz,
497 int mode) throw(std::bad_alloc)
498 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_AXIS)
500 rawstate = 0;
501 digitalstate = 0;
502 last_tolerance = 0.5;
503 _mode = mode;
505 key_axis::~key_axis() throw() {}
507 int32_t key_axis::get_state() const throw()
509 threads::arlock u(get_keyboard_lock());
510 return rawstate;
513 int32_t key_axis::get_state_digital() const throw()
515 threads::arlock u(get_keyboard_lock());
516 if(rawstate <= -32768 * last_tolerance)
517 return -1;
518 if(rawstate >= 32767 * last_tolerance)
519 return 1;
520 return 0;
523 int key_axis::get_mode() const throw()
525 threads::arlock u(get_keyboard_lock());
526 return _mode;
529 std::vector<std::string> key_axis::get_subkeys() throw(std::bad_alloc)
531 threads::arlock u(get_keyboard_lock());
532 std::vector<std::string> r;
533 if(_mode == 0)
534 r.push_back("");
535 else if(_mode > 0) {
536 r.push_back("+");
537 r.push_back("-");
539 return r;
542 void key_axis::set_state(modifier_set mods, int32_t _rawstate) throw()
544 bool edge = false;
545 int32_t state;
546 uint32_t change = 0;
547 int dold = 0, dnew = 0;
548 get_keyboard_lock().lock();
549 if(rawstate != _rawstate) {
550 dold = digitalstate;
551 rawstate = _rawstate;
552 state = rawstate;
553 if(state <= -32768 * last_tolerance)
554 dnew = -1;
555 if(state >= 32767 * last_tolerance)
556 dnew = 1;
557 digitalstate = dnew;
558 if(dnew > 0)
559 change |= 1;
560 if((dold > 0 && dnew <= 0) || (dold <= 0 && dnew > 0))
561 change |= 2;
562 if(dnew < 0)
563 change |= 4;
564 if((dold < 0 && dnew >= 0) || (dold >= 0 && dnew < 0))
565 change |= 8;
566 edge = true;
568 get_keyboard_lock().unlock();
569 if(edge) {
570 event_axis e(state, change);
571 call_listeners(mods, e);
575 void key_axis::set_mode(int mode, double tolerance) throw()
577 threads::arlock u(get_keyboard_lock());
578 _mode = mode;
579 last_tolerance = tolerance;
582 key_mouse::key_mouse(keyboard& keyb, const std::string& name, const std::string& clazz,
583 mouse_calibration _cal) throw(std::bad_alloc)
584 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_MOUSE)
586 rawstate = 0;
587 cal = _cal;
590 key_mouse::~key_mouse() throw() {}
591 int32_t key_mouse::get_state_digital() const throw() { return 0; }
593 int32_t key_mouse::get_state() const throw()
595 threads::arlock u(get_keyboard_lock());
596 return cal.get_calibrated_value(rawstate);
599 std::vector<std::string> key_mouse::get_subkeys() throw(std::bad_alloc)
601 return std::vector<std::string>();
604 mouse_calibration key_mouse::get_calibration() const throw()
606 threads::arlock u(get_keyboard_lock());
607 mouse_calibration tmp = cal;
608 return tmp;
611 void key_mouse::set_state(modifier_set mods, int32_t _rawstate) throw()
613 bool edge = false;
614 int32_t state;
615 mouse_calibration _cal;
616 get_keyboard_lock().lock();
617 if(rawstate != _rawstate) {
618 rawstate = _rawstate;
619 state = cal.get_calibrated_value(rawstate);
620 _cal = cal;
621 edge = true;
623 get_keyboard_lock().unlock();
624 if(edge) {
625 event_mouse e(state, _cal);
626 call_listeners(mods, e);
630 void key_mouse::set_calibration(mouse_calibration _cal) throw()
632 get_keyboard_lock().lock();
633 cal = _cal;
634 int32_t state = cal.get_calibrated_value(rawstate);
635 get_keyboard_lock().unlock();
636 event_mouse e(state, _cal);
637 modifier_set mods;
638 call_listeners(mods, e);