2 #include "integer-pool.hpp"
3 #include "keyboard-mapper.hpp"
4 #include "register-queue.hpp"
5 #include "stateobject.hpp"
12 threads::rlock
* global_lock
;
13 threads::rlock
& get_keymap_lock()
15 if(!global_lock
) global_lock
= new threads::rlock
;
21 std::map
<std::string
, invbind_info
*> invbinds
;
22 std::set
<set_listener
*> callbacks
;
25 typedef stateobject::type
<invbind_set
, set_internal
> set_internal_t
;
28 set_listener::~set_listener()
32 std::string
mapper::fixup_command_polarity(std::string cmd
, bool polarity
) throw(std::bad_alloc
)
34 if(cmd
== "" || cmd
== "*")
37 if(cmd
[0] != '+' && polarity
)
39 if(cmd
[0] == '+' && !polarity
)
42 if(cmd
[1] != '+' && polarity
)
44 if(cmd
[1] == '+' && !polarity
)
50 keyspec::keyspec() throw(std::bad_alloc
)
54 keyspec::keyspec(const std::string
& keyspec
) throw(std::bad_alloc
, std::runtime_error
)
56 regex_results r
= regex("([^/]*)/([^|]*)\\|(.*)", keyspec
, "Invalid keyspec");
62 keyspec::operator std::string() throw(std::bad_alloc
)
64 return mod
+ "/" + mask
+ "|" + key
;
67 keyspec::operator bool() throw()
72 bool keyspec::operator!() throw()
77 void keyspec::clear() throw()
84 bool keyspec::operator==(const keyspec
& keyspec
)
86 return (mod
== keyspec
.mod
&& mask
== keyspec
.mask
&& key
== keyspec
.key
);
89 bool keyspec::operator!=(const keyspec
& keyspec
)
91 return (mod
!= keyspec
.mod
|| mask
!= keyspec
.mask
|| key
!= keyspec
.key
);
94 std::set
<invbind
*> mapper::get_inverses() throw(std::bad_alloc
)
96 threads::arlock
u(get_keymap_lock());
103 invbind
* mapper::get_inverse(const std::string
& command
) throw(std::bad_alloc
)
105 threads::arlock
u(get_keymap_lock());
106 if(ibinds
.count(command
))
107 return ibinds
[command
];
112 std::set
<ctrlrkey
*> mapper::get_controller_keys() throw(std::bad_alloc
)
114 threads::arlock
u(get_keymap_lock());
115 std::set
<ctrlrkey
*> r
;
121 ctrlrkey
* mapper::get_controllerkey(const std::string
& command
) throw(std::bad_alloc
)
123 threads::arlock
u(get_keymap_lock());
124 if(ckeys
.count(command
))
125 return ckeys
[command
];
130 void mapper::do_register(const std::string
& name
, invbind
& ibind
) throw(std::bad_alloc
)
132 threads::arlock
u(get_keymap_lock());
133 ibinds
[name
] = &ibind
;
134 //Search for matches.
135 for(auto i
: bindings
)
136 if(i
.second
== ibind
.cmd
) {
137 ibind
.specs
.push_back(i
.first
.as_keyspec());
141 void mapper::do_unregister(const std::string
& name
, invbind
* dummy
) throw(std::bad_alloc
)
143 if(dtor_running
) return;
144 threads::arlock
u(get_keymap_lock());
148 void mapper::do_register(const std::string
& name
, ctrlrkey
& ckey
) throw(std::bad_alloc
)
150 threads::arlock
u(get_keymap_lock());
154 void mapper::do_unregister(const std::string
& name
, ctrlrkey
* dummy
) throw(std::bad_alloc
)
156 threads::arlock
u(get_keymap_lock());
160 keyboard
& mapper::get_keyboard() throw()
165 mapper::mapper(keyboard
& _kbd
, command::group
& _domain
) throw(std::bad_alloc
)
166 : _listener(*this), kbd(_kbd
), domain(_domain
)
168 register_queue
<mapper
, invbind
>::do_ready(*this, true);
169 register_queue
<mapper
, ctrlrkey
>::do_ready(*this, true);
172 mapper::~mapper() throw()
175 threads::arlock
u(get_keymap_lock());
177 i
.second
->mapper_died();
178 for(auto i
: invbind_set_cbs
)
179 i
->drop_callback(_listener
);
180 register_queue
<mapper
, invbind
>::do_ready(*this, false);
181 register_queue
<mapper
, ctrlrkey
>::do_ready(*this, false);
184 mapper::triplet::triplet(modifier_set _mod
, modifier_set _mask
, key
& kkey
,
194 mapper::triplet::triplet(key
& kkey
, unsigned _subkey
)
201 bool mapper::triplet::operator<(const struct triplet
& a
) const
203 if((uint64_t)_key
< (uint64_t)a
._key
)
205 if((uint64_t)_key
> (uint64_t)a
._key
)
207 if(subkey
< a
.subkey
)
209 if(subkey
> a
.subkey
)
211 if(index
&& !a
.index
)
213 if(!index
&& a
.index
)
226 bool mapper::triplet::operator==(const struct triplet
& a
) const
232 if(subkey
!= a
.subkey
)
236 if(!(mask
== a
.mask
))
241 keyspec
mapper::triplet::as_keyspec() const throw(std::bad_alloc
)
246 auto s
= _key
->get_subkeys();
247 if(s
.size() > subkey
)
248 k
.key
= _key
->get_name() + s
[subkey
];
250 k
.key
= _key
->get_name();
254 std::list
<keyspec
> mapper::get_bindings() throw(std::bad_alloc
)
256 threads::arlock
u(get_keymap_lock());
257 std::list
<keyspec
> r
;
258 for(auto i
: bindings
)
259 r
.push_back(i
.first
.as_keyspec());
263 command::group
& mapper::get_command_group() throw()
268 void mapper::bind(std::string mod
, std::string modmask
, std::string keyname
, std::string command
)
269 throw(std::bad_alloc
, std::runtime_error
)
275 triplet
t(kbd
, spec
);
276 threads::arlock
u(get_keymap_lock());
277 if(bindings
.count(t
))
278 throw std::runtime_error("Key is already bound");
279 if(!listening
.count(t
._key
)) {
280 t
._key
->add_listener(*this, false);
281 listening
.insert(t
._key
);
283 std::string old_command
;
284 if(bindings
.count(t
))
285 old_command
= bindings
[t
];
286 bindings
[t
] = command
;
287 change_command(spec
, old_command
, command
);
290 void mapper::unbind(std::string mod
, std::string modmask
, std::string keyname
) throw(std::bad_alloc
,
297 triplet
t(kbd
, spec
);
298 threads::arlock
u(get_keymap_lock());
299 if(!bindings
.count(t
))
300 throw std::runtime_error("Key is not bound");
301 //No harm at leaving listeners listening.
302 std::string old_command
;
303 if(bindings
.count(t
))
304 old_command
= bindings
[t
];
306 change_command(spec
, old_command
, "");
309 std::string
mapper::get(const keyspec
& keyspec
) throw(std::bad_alloc
)
311 triplet
t(kbd
, keyspec
);
312 threads::arlock
u(get_keymap_lock());
313 if(!bindings
.count(t
))
318 void mapper::change_command(const keyspec
& spec
, const std::string
& old
, const std::string
& newc
)
320 threads::arlock
u(get_keymap_lock());
321 if(old
!= "" && ibinds
.count(old
)) {
322 auto& i
= ibinds
[old
];
326 for(auto j
: bindings
)
327 if(j
.second
== i
->cmd
&& j
.first
.as_keyspec() != spec
) {
328 i
->specs
.push_back(j
.first
.as_keyspec());
331 if(newc
!= "" && ibinds
.count(newc
)) {
332 auto& i
= ibinds
[newc
];
333 i
->specs
.push_back(spec
);
337 void mapper::set(const keyspec
& keyspec
, const std::string
& cmd
) throw(std::bad_alloc
,
340 triplet
t(kbd
, keyspec
);
341 threads::arlock
u(get_keymap_lock());
342 if(!listening
.count(t
._key
)) {
343 t
._key
->add_listener(*this, false);
344 listening
.insert(t
._key
);
347 if(bindings
.count(t
))
348 oldcmd
= bindings
[t
];
350 change_command(keyspec
, oldcmd
, cmd
);
353 void mapper::on_key_event(modifier_set
& mods
, key
& key
, event
& event
)
355 auto mask
= event
.get_change_mask();
358 unsigned k
= mask
& 3;
360 on_key_event_subkey(mods
, key
, i
, k
== 3);
366 void mapper::on_key_event_subkey(modifier_set
& mods
, key
& key
, unsigned skey
,
369 triplet
llow(key
, skey
);
370 triplet
lhigh(key
, skey
+ 1);
371 auto low
= bindings
.lower_bound(llow
);
372 auto high
= bindings
.lower_bound(lhigh
);
373 for(auto i
= low
; i
!= high
; i
++) {
374 if(!mods
.triggers(i
->first
.mod
, i
->first
.mask
))
376 std::string cmd
= fixup_command_polarity(i
->second
, polarity
);
382 mapper::triplet::triplet(keyboard
& k
, const keyspec
& spec
)
384 mod
= modifier_set::construct(k
, spec
.mod
);
385 mask
= modifier_set::construct(k
, spec
.mask
);
387 throw std::runtime_error("Bad modifiers");
388 auto g
= keymapper_lookup_subkey(k
, spec
.key
, false);
394 std::list
<ctrlrkey
*> mapper::get_controllerkeys_kbdkey(key
* kbdkey
)
395 throw(std::bad_alloc
)
397 threads::arlock
u(get_keymap_lock());
398 std::list
<ctrlrkey
*> r
;
399 for(auto i
: ckeys
) {
400 for(unsigned j
= 0;; j
++) {
401 auto k
= i
.second
->get(j
);
404 if(k
.first
== kbdkey
)
405 r
.push_back(i
.second
);
411 void mapper::add_invbind_set(invbind_set
& set
)
413 threads::arlock
u(get_keymap_lock());
414 if(invbind_set_cbs
.count(&set
)) return;
416 invbind_set_cbs
.insert(&set
);
417 set
.add_callback(_listener
);
419 invbind_set_cbs
.erase(&set
);
423 void mapper::drop_invbind_set(invbind_set
& set
)
425 threads::arlock
h(get_keymap_lock());
426 //Drop the callback. This unregisters all.
427 set
.drop_callback(_listener
);
428 invbind_set_cbs
.erase(&set
);
431 mapper::listener::listener(mapper
& _grp
)
436 mapper::listener::~listener()
440 void mapper::listener::create(invbind_set
& s
, const std::string
& name
, invbind_info
& ibinfo
)
442 threads::arlock
h(get_keymap_lock());
446 void mapper::listener::destroy(invbind_set
& s
, const std::string
& name
)
448 threads::arlock
h(get_keymap_lock());
449 if(grp
.dtor_running
) return;
450 grp
.ibinds
.erase(name
);
453 void mapper::listener::kill(invbind_set
& s
)
455 threads::arlock
h(get_keymap_lock());
456 if(grp
.dtor_running
) return;
457 grp
.invbind_set_cbs
.erase(&s
);
460 invbind::invbind(mapper
& kmapper
, const std::string
& _command
, const std::string
& _name
, bool dynamic
)
461 throw(std::bad_alloc
)
462 : _mapper(&kmapper
), cmd(_command
), oname(_name
)
464 is_dynamic
= dynamic
;
465 register_queue
<mapper
, invbind
>::do_register(*_mapper
, cmd
, *this);
468 invbind::~invbind() throw()
470 register_queue
<mapper
, invbind
>::do_unregister(*_mapper
, cmd
);
473 keyspec
invbind::get(unsigned index
) throw(std::bad_alloc
)
475 threads::arlock
u(get_keymap_lock());
476 if(index
>= specs
.size())
481 void invbind::clear(unsigned index
) throw(std::bad_alloc
)
483 threads::arlock
u(get_keymap_lock());
486 if(index
>= specs
.size())
488 unbind
= specs
[index
];
490 if(unbind
&& _mapper
)
491 _mapper
->set(unbind
, "");
494 void invbind::append(const keyspec
& keyspec
) throw(std::bad_alloc
)
496 threads::arlock
u(get_keymap_lock());
497 _mapper
->set(keyspec
, cmd
);
500 std::string
invbind::getname() throw(std::bad_alloc
)
505 void invbind::mapper_died()
507 threads::arlock
u(get_keymap_lock());
509 if(is_dynamic
) delete this;
512 invbind_info::invbind_info(invbind_set
& set
, const std::string
& _command
, const std::string
& _name
)
513 throw(std::bad_alloc
)
518 in_set
->do_register(command
, *this);
521 invbind_info::~invbind_info() throw()
523 threads::arlock
u(get_keymap_lock());
525 in_set
->do_unregister(command
, *this);
528 invbind
* invbind_info::make(mapper
& m
)
530 return new invbind(m
, command
, name
, true);
533 void invbind_info::set_died()
535 threads::arlock
u(get_keymap_lock());
539 invbind_set::invbind_set()
543 invbind_set::~invbind_set()
545 auto state
= set_internal_t::get_soft(this);
547 threads::arlock
u(get_keymap_lock());
548 //Call all DCBs on all factories.
549 for(auto i
: state
->invbinds
)
550 for(auto j
: state
->callbacks
)
551 j
->destroy(*this, i
.first
);
553 for(auto j
: state
->callbacks
)
555 //Notify all factories that base set died.
556 for(auto i
: state
->invbinds
)
557 i
.second
->set_died();
558 //We assume factories look after themselves, so we don't destroy those.
559 set_internal_t::clear(this);
562 void invbind_set::do_register(const std::string
& name
, invbind_info
& info
)
564 threads::arlock
u(get_keymap_lock());
565 auto& state
= set_internal_t::get(this);
566 if(state
.invbinds
.count(name
)) {
567 std::cerr
<< "WARNING: Command collision for " << name
<< "!" << std::endl
;
570 state
.invbinds
[name
] = &info
;
571 //Call all CCBs on this.
572 for(auto i
: state
.callbacks
)
573 i
->create(*this, name
, info
);
576 void invbind_set::do_unregister(const std::string
& name
, invbind_info
& info
)
578 threads::arlock
u(get_keymap_lock());
579 auto state
= set_internal_t::get_soft(this);
581 if(!state
->invbinds
.count(name
) || state
->invbinds
[name
] != &info
) return; //Not this.
582 state
->invbinds
.erase(name
);
583 //Call all DCBs on this.
584 for(auto i
: state
->callbacks
)
585 i
->destroy(*this, name
);
588 void invbind_set::add_callback(set_listener
& listener
) throw(std::bad_alloc
)
590 threads::arlock
u(get_keymap_lock());
591 auto& state
= set_internal_t::get(this);
592 state
.callbacks
.insert(&listener
);
593 //To avoid races, call CCBs on all factories for this.
594 for(auto j
: state
.invbinds
)
595 listener
.create(*this, j
.first
, *j
.second
);
598 void invbind_set::drop_callback(set_listener
& listener
)
600 threads::arlock
u(get_keymap_lock());
601 auto state
= set_internal_t::get_soft(this);
603 if(state
->callbacks
.count(&listener
)) {
604 //To avoid races, call DCBs on all factories for this.
605 for(auto j
: state
->invbinds
)
606 listener
.destroy(*this, j
.first
);
607 state
->callbacks
.erase(&listener
);
611 ctrlrkey::ctrlrkey(mapper
& kmapper
, const std::string
& _command
, const std::string
& _name
,
612 bool _axis
) throw(std::bad_alloc
)
613 : _mapper(kmapper
), cmd(_command
), oname(_name
)
615 register_queue
<mapper
, ctrlrkey
>::do_register(_mapper
, cmd
, *this);
619 ctrlrkey::~ctrlrkey() throw()
621 register_queue
<mapper
, ctrlrkey
>::do_unregister(_mapper
, cmd
);
624 std::pair
<key
*, unsigned> ctrlrkey::get(unsigned index
) throw()
626 threads::arlock
u(get_keymap_lock());
627 if(index
>= keys
.size())
628 return std::make_pair(reinterpret_cast<key
*>(NULL
), 0);
632 std::string
ctrlrkey::get_string(unsigned index
) throw(std::bad_alloc
)
637 auto s
= k
.first
->get_subkeys();
638 if(k
.second
>= s
.size() || axis
)
639 return k
.first
->get_name();
640 return k
.first
->get_name() + s
[k
.second
];
643 void ctrlrkey::append(key
* _key
, unsigned _subkey
) throw()
645 threads::arlock
u(get_keymap_lock());
646 //Search for duplicates.
647 std::pair
<key
*, unsigned> mkey
= std::make_pair(_key
, _subkey
);
652 _key
->add_listener(*this, axis
);
653 keys
.push_back(mkey
);
656 void ctrlrkey::remove(key
* _key
, unsigned _subkey
) throw()
658 threads::arlock
u(get_keymap_lock());
659 std::pair
<key
*, unsigned> mkey
= std::make_pair(_key
, _subkey
);
660 for(auto i
= keys
.begin(); i
!= keys
.end(); i
++) {
662 mkey
.first
->remove_listener(*this);
669 void ctrlrkey::append(const std::string
& _key
) throw(std::bad_alloc
, std::runtime_error
)
671 auto g
= keymapper_lookup_subkey(_mapper
.get_keyboard(), _key
, axis
);
672 append(g
.first
, g
.second
);
675 std::pair
<key
*, unsigned> keymapper_lookup_subkey(keyboard
& kbd
, const std::string
& name
,
676 bool axis
) throw(std::bad_alloc
, std::runtime_error
)
678 threads::arlock
u(get_keymap_lock());
680 return std::make_pair((key
*)NULL
, 0);
681 //Try direct lookup first.
682 key
* key
= kbd
.try_lookup_key(name
);
684 return std::make_pair(key
, 0);
685 //Axes only do direct lookup.
687 throw std::runtime_error("Invalid key");
688 std::string prefix
= name
;
689 char letter
= prefix
[prefix
.length() - 1];
690 prefix
= prefix
.substr(0, prefix
.length() - 1);
691 key
= kbd
.try_lookup_key(prefix
);
693 throw std::runtime_error("Invalid key");
694 auto s
= key
->get_subkeys();
695 for(size_t i
= 0; i
< s
.size(); i
++)
696 if(s
[i
].length() > 0 && letter
== s
[i
][0])
697 return std::make_pair(key
, i
);
698 throw std::runtime_error("Invalid key");
701 void ctrlrkey::on_key_event(modifier_set
& mods
, key
& key
, event
& event
)
704 //Axes work specially.
705 _mapper
.get_command_group().invoke((stringfmt() << cmd
<< " " << event
.get_state()).str());
708 auto mask
= event
.get_change_mask();
712 unsigned kmask
= (mask
>> (2 * i
.second
)) & 3;
715 cmd2
= mapper::fixup_command_polarity(cmd
, kmask
== 3);
717 _mapper
.get_command_group().invoke(cmd2
);