Actually call on_reset callback
[lsnes.git] / src / library / keyboard.cpp
blobc020ad4824a2024336025b3cf7beb3f93329c416
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)
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)
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()
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)
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)
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()
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()
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)
147 if(really)
148 set.insert(&mod);
151 void modifier_set::remove(modifier& mod, bool really)
153 if(really)
154 set.erase(&mod);
157 modifier_set modifier_set::construct(keyboard& kbd, const std::string& _modifiers)
159 modifier_set set;
160 std::string modifiers = _modifiers;
161 while(modifiers != "") {
162 std::string mod = modifiers;
163 std::string rest;
164 size_t split = modifiers.find_first_of(",");
165 if(split < modifiers.length()) {
166 mod = modifiers.substr(0, split);
167 rest = modifiers.substr(split + 1);
169 set.add(kbd.lookup_modifier(mod));
170 modifiers = rest;
172 return set;
175 bool modifier_set::valid(modifier_set& mask)
177 //No element can be together with its linkage group.
178 for(auto i : set) {
179 modifier* j = i->get_link();
180 if(j && set.count(j))
181 return false;
183 for(auto i : mask.set) {
184 modifier* j = i->get_link();
185 if(j && mask.set.count(j))
186 return false;
188 //For every element of set, it or its linkage group must be in mask.
189 for(auto i : set) {
190 modifier* j = i->get_link();
191 if(!mask.set.count(i) && !mask.set.count(j ? j : i))
192 return false;
194 return true;
197 bool modifier_set::operator==(const modifier_set& m) const throw()
199 for(auto i : set)
200 if(!m.set.count(i))
201 return false;
202 for(auto i : m.set)
203 if(!set.count(i))
204 return false;
205 return true;
208 bool modifier_set::operator<(const modifier_set& m) const throw()
210 auto i1 = set.begin();
211 auto i2 = m.set.begin();
212 for(; i1 != set.end() && i2 != m.set.end(); i1++, i2++) {
213 if((uint64_t)*i1 < (uint64_t)*i2)
214 return true;
215 if((uint64_t)*i1 > (uint64_t)*i2)
216 return false;
218 return (i2 != m.set.end());
221 modifier_set::operator std::string() const
223 std::string r;
224 for(auto i : set)
225 r = r + ((r != "") ? "," : "") + i->get_name();
226 return r;
229 std::ostream& operator<<(std::ostream& os, const modifier_set& m)
231 os << "<modset:";
232 for(auto i : m.set)
233 os << i->get_name() << " ";
234 os << ">";
235 return os;
238 bool modifier_set::triggers(const modifier_set& trigger, const modifier_set& mask)
240 for(auto i : mask.set) {
241 bool trigger_exact = trigger.set.count(i);
242 bool trigger_ingroup = false;
243 for(auto j : trigger.set)
244 if(j->get_link() == i)
245 trigger_ingroup = true;
246 bool trigger_none = !trigger_exact && !trigger_ingroup;
248 //If trigger_exact is set, then this key or a key in this group must be pressed.
249 if(trigger_exact) {
250 bool any = false;
251 for(auto j : set)
252 any = any || (j == i || j->get_link() == i);
253 if(!any)
254 return false;
256 //If trigger_ingroup is set, then exactly that set of keys in group must be pressed.
257 if(trigger_ingroup) {
258 for(auto j : i->get_keyboard().all_modifiers()) {
259 if(j->get_link() != i)
260 continue; //Not interested.
261 if((set.count(j) > 0) != (trigger.set.count(j) > 0))
262 return false;
265 //If trigger_none is set, then this key nor keys in this key group can't be pressed.
266 if(trigger_none) {
267 bool any = false;
268 for(auto j : set)
269 any = any || (j == i || j->get_link() == i);
270 if(any)
271 return false;
274 return true;
277 int32_t mouse_calibration::get_calibrated_value(int32_t x) const throw()
279 return x - offset;
282 event::~event() throw() {}
283 event_key::~event_key() throw() {}
284 event_axis::~event_axis() throw() {}
285 event_hat::~event_hat() throw() {}
286 event_mouse::~event_mouse() throw() {}
287 event_listener::~event_listener() throw() {}
289 key::~key() throw()
291 kbd.do_unregister(name, *this);
294 event_key::event_key(uint32_t chngmask)
295 : event(chngmask, keytype::KBD_KEYTYPE_KEY)
299 event_axis::event_axis(int32_t _state, uint32_t chngmask)
300 : event(chngmask, keytype::KBD_KEYTYPE_AXIS)
302 state = _state;
305 event_hat::event_hat(uint32_t chngmask)
306 : event(chngmask, keytype::KBD_KEYTYPE_HAT)
310 event_mouse::event_mouse(int32_t _state, const mouse_calibration& _cal)
311 : event(0, keytype::KBD_KEYTYPE_MOUSE)
313 state = _state;
314 cal = _cal;
317 int32_t event_key::get_state() const throw() { return (get_change_mask() & 1) != 0; }
318 int32_t event_axis::get_state() const throw() { return state; }
319 int32_t event_mouse::get_state() const throw() { return state; }
321 int32_t event_hat::get_state() const throw()
323 int32_t r = 0;
324 uint32_t m = get_change_mask();
325 if(m & 1) r |= 1;
326 if(m & 4) r |= 2;
327 if(m & 16) r |= 4;
328 if(m & 64) r |= 8;
329 return m;
332 key::key(keyboard& keyb, const std::string& _name, const std::string& _clazz,
333 keytype _type)
334 : kbd(keyb), clazz(_clazz), name(_name), type(_type)
336 exclusive_listener = NULL;
337 kbd.do_register(name, *this);
340 void key::add_listener(event_listener& listener, bool analog)
342 if(analog) {
343 analog_listeners.insert(&listener);
344 digital_listeners.erase(&listener);
345 } else {
346 digital_listeners.insert(&listener);
347 analog_listeners.erase(&listener);
350 void key::remove_listener(event_listener& listener) throw()
352 digital_listeners.erase(&listener);
353 analog_listeners.erase(&listener);
356 void key::set_exclusive(event_listener* listener) throw()
358 threads::arlock u(get_keyboard_lock());
359 exclusive_listener = listener;
362 void key::call_listeners(modifier_set& mods, event& event)
364 kbd.set_current_key(this);
365 bool digital = (event.get_change_mask() & 0xAAAAAAAAUL) != 0;
366 get_keyboard_lock().lock();
367 if(exclusive_listener) {
368 get_keyboard_lock().unlock();
369 exclusive_listener->on_key_event(mods, *this, event);
370 kbd.set_current_key(NULL);
371 return;
373 event_listener* itr = NULL;
374 while(digital) {
375 auto itr2 = digital_listeners.upper_bound(itr);
376 if(itr2 == digital_listeners.end())
377 break;
378 itr = *itr2;
379 get_keyboard_lock().unlock();
380 itr->on_key_event(mods, *this, event);
381 get_keyboard_lock().lock();
383 itr = NULL;
384 while(true) {
385 auto itr2 = analog_listeners.upper_bound(itr);
386 if(itr2 == analog_listeners.end())
387 break;
388 itr = *itr2;
389 get_keyboard_lock().unlock();
390 itr->on_key_event(mods, *this, event);
391 get_keyboard_lock().lock();
393 get_keyboard_lock().unlock();
394 kbd.set_current_key(NULL);
397 key_axis* key::cast_axis() throw()
399 if(type != KBD_KEYTYPE_AXIS)
400 return NULL;
401 return dynamic_cast<key_axis*>(this);
404 key_mouse* key::cast_mouse() throw()
406 if(type != KBD_KEYTYPE_MOUSE)
407 return NULL;
408 return dynamic_cast<key_mouse*>(this);
411 key_key::key_key(keyboard& keyb, const std::string& name, const std::string& clazz)
412 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_KEY)
414 state = 0;
417 key_key::~key_key() throw() {}
419 void key_key::set_state(modifier_set mods, int32_t _state) throw()
421 uint32_t change = _state ? 1 : 0;
422 bool edge = false;
423 get_keyboard_lock().lock();
424 if(state != _state) {
425 state = _state;
426 change |= 2;
427 edge = true;
429 get_keyboard_lock().unlock();
430 if(edge) {
431 event_key e(change);
432 call_listeners(mods, e);
436 int32_t key_key::get_state() const throw() { return state; }
437 int32_t key_key::get_state_digital() const throw() { return state; }
439 std::vector<std::string> key_key::get_subkeys()
441 std::vector<std::string> r;
442 r.push_back("");
443 return r;
446 key_hat::key_hat(keyboard& keyb, const std::string& name, const std::string& clazz)
447 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_HAT)
449 state = 0;
451 key_hat::~key_hat() throw() {}
453 void key_hat::set_state(modifier_set mods, int32_t _state) throw()
455 state &= 15;
456 uint32_t change = 0;
457 bool edge = false;
458 get_keyboard_lock().lock();
459 if(state != _state) {
460 int32_t schange = state ^ _state;
461 state = _state;
462 if(state & 1) change |= 1;
463 if(schange & 1) change |= 2;
464 if(state & 2) change |= 4;
465 if(schange & 2) change |= 8;
466 if(state & 4) change |= 16;
467 if(schange & 4) change |= 32;
468 if(state & 8) change |= 64;
469 if(schange & 8) change |= 128;
470 edge = true;
472 get_keyboard_lock().unlock();
473 if(edge) {
474 event_hat e(change);
475 call_listeners(mods, e);
479 int32_t key_hat::get_state() const throw() { return state; }
480 int32_t key_hat::get_state_digital() const throw() { return state; }
482 std::vector<std::string> key_hat::get_subkeys()
484 std::vector<std::string> r;
485 r.push_back("n");
486 r.push_back("e");
487 r.push_back("s");
488 r.push_back("w");
489 return r;
492 key_axis::key_axis(keyboard& keyb, const std::string& name, const std::string& clazz,
493 int mode)
494 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_AXIS)
496 rawstate = 0;
497 digitalstate = 0;
498 last_tolerance = 0.5;
499 _mode = mode;
501 key_axis::~key_axis() throw() {}
503 int32_t key_axis::get_state() const throw()
505 threads::arlock u(get_keyboard_lock());
506 return rawstate;
509 int32_t key_axis::get_state_digital() const throw()
511 threads::arlock u(get_keyboard_lock());
512 if(rawstate <= -32768 * last_tolerance)
513 return -1;
514 if(rawstate >= 32767 * last_tolerance)
515 return 1;
516 return 0;
519 int key_axis::get_mode() const throw()
521 threads::arlock u(get_keyboard_lock());
522 return _mode;
525 std::vector<std::string> key_axis::get_subkeys()
527 threads::arlock u(get_keyboard_lock());
528 std::vector<std::string> r;
529 if(_mode == 0)
530 r.push_back("");
531 else if(_mode > 0) {
532 r.push_back("+");
533 r.push_back("-");
535 return r;
538 void key_axis::set_state(modifier_set mods, int32_t _rawstate) throw()
540 bool edge = false;
541 int32_t state;
542 uint32_t change = 0;
543 int dold = 0, dnew = 0;
544 get_keyboard_lock().lock();
545 if(rawstate != _rawstate) {
546 dold = digitalstate;
547 rawstate = _rawstate;
548 state = rawstate;
549 if(state <= -32768 * last_tolerance)
550 dnew = -1;
551 if(state >= 32767 * last_tolerance)
552 dnew = 1;
553 digitalstate = dnew;
554 if(dnew > 0)
555 change |= 1;
556 if((dold > 0 && dnew <= 0) || (dold <= 0 && dnew > 0))
557 change |= 2;
558 if(dnew < 0)
559 change |= 4;
560 if((dold < 0 && dnew >= 0) || (dold >= 0 && dnew < 0))
561 change |= 8;
562 edge = true;
564 get_keyboard_lock().unlock();
565 if(edge) {
566 event_axis e(state, change);
567 call_listeners(mods, e);
571 void key_axis::set_mode(int mode, double tolerance) throw()
573 threads::arlock u(get_keyboard_lock());
574 _mode = mode;
575 last_tolerance = tolerance;
578 key_mouse::key_mouse(keyboard& keyb, const std::string& name, const std::string& clazz,
579 mouse_calibration _cal)
580 : key(keyb, name, clazz, keytype::KBD_KEYTYPE_MOUSE)
582 rawstate = 0;
583 cal = _cal;
586 key_mouse::~key_mouse() throw() {}
587 int32_t key_mouse::get_state_digital() const throw() { return 0; }
589 int32_t key_mouse::get_state() const throw()
591 threads::arlock u(get_keyboard_lock());
592 return cal.get_calibrated_value(rawstate);
595 std::vector<std::string> key_mouse::get_subkeys()
597 return std::vector<std::string>();
600 mouse_calibration key_mouse::get_calibration() const throw()
602 threads::arlock u(get_keyboard_lock());
603 mouse_calibration tmp = cal;
604 return tmp;
607 void key_mouse::set_state(modifier_set mods, int32_t _rawstate) throw()
609 bool edge = false;
610 int32_t state;
611 mouse_calibration _cal;
612 get_keyboard_lock().lock();
613 if(rawstate != _rawstate) {
614 rawstate = _rawstate;
615 state = cal.get_calibrated_value(rawstate);
616 _cal = cal;
617 edge = true;
619 get_keyboard_lock().unlock();
620 if(edge) {
621 event_mouse e(state, _cal);
622 call_listeners(mods, e);
626 void key_mouse::set_calibration(mouse_calibration _cal) throw()
628 get_keyboard_lock().lock();
629 cal = _cal;
630 int32_t state = cal.get_calibrated_value(rawstate);
631 get_keyboard_lock().unlock();
632 event_mouse e(state, _cal);
633 modifier_set mods;
634 call_listeners(mods, e);