1 #include "keymapper.hpp"
2 #include "register-queue.hpp"
5 std::string
keyboard_mapper::fixup_command_polarity(std::string cmd
, bool polarity
) throw(std::bad_alloc
)
7 if(cmd
== "" || cmd
== "*")
10 if(cmd
[0] != '+' && polarity
)
12 if(cmd
[0] == '+' && !polarity
)
15 if(cmd
[1] != '+' && polarity
)
17 if(cmd
[1] == '+' && !polarity
)
23 key_specifier::key_specifier() throw(std::bad_alloc
)
27 key_specifier::key_specifier(const std::string
& keyspec
) throw(std::bad_alloc
, std::runtime_error
)
29 regex_results r
= regex("([^/]*)/([^|]*)\\|(.*)", keyspec
, "Invalid keyspec");
35 key_specifier::operator std::string() throw(std::bad_alloc
)
37 return mod
+ "/" + mask
+ "|" + key
;
40 key_specifier::operator bool() throw()
45 bool key_specifier::operator!() throw()
50 void key_specifier::clear() throw()
57 bool key_specifier::operator==(const key_specifier
& keyspec
)
59 return (mod
== keyspec
.mod
&& mask
== keyspec
.mask
&& key
== keyspec
.key
);
62 bool key_specifier::operator!=(const key_specifier
& keyspec
)
64 return (mod
!= keyspec
.mod
|| mask
!= keyspec
.mask
|| key
!= keyspec
.key
);
67 std::set
<inverse_bind
*> keyboard_mapper::get_inverses() throw(std::bad_alloc
)
69 umutex_class
u(mutex
);
70 std::set
<inverse_bind
*> r
;
76 inverse_bind
* keyboard_mapper::get_inverse(const std::string
& command
) throw(std::bad_alloc
)
78 umutex_class
u(mutex
);
79 if(ibinds
.count(command
))
80 return ibinds
[command
];
85 std::set
<controller_key
*> keyboard_mapper::get_controller_keys() throw(std::bad_alloc
)
87 umutex_class
u(mutex
);
88 std::set
<controller_key
*> r
;
94 controller_key
* keyboard_mapper::get_controllerkey(const std::string
& command
) throw(std::bad_alloc
)
96 umutex_class
u(mutex
);
97 if(ckeys
.count(command
))
98 return ckeys
[command
];
103 void keyboard_mapper::do_register_inverse(const std::string
& name
, inverse_bind
& ibind
) throw(std::bad_alloc
)
105 umutex_class
u(mutex
);
106 ibinds
[name
] = &ibind
;
107 //Search for matches.
108 for(auto i
: bindings
)
109 if(i
.second
== ibind
.cmd
) {
110 umutex_class
u2(ibind
.mutex
);
111 ibind
.specs
.push_back(i
.first
.as_keyspec());
115 void keyboard_mapper::do_unregister_inverse(const std::string
& name
) throw(std::bad_alloc
)
117 umutex_class
u(mutex
);
121 void keyboard_mapper::do_register_ckey(const std::string
& name
, controller_key
& ckey
) throw(std::bad_alloc
)
123 umutex_class
u(mutex
);
127 void keyboard_mapper::do_unregister_ckey(const std::string
& name
) throw(std::bad_alloc
)
129 umutex_class
u(mutex
);
133 keyboard
& keyboard_mapper::get_keyboard() throw()
138 keyboard_mapper::keyboard_mapper(keyboard
& _kbd
, command_group
& _domain
) throw(std::bad_alloc
)
139 : inverse_proxy(*this), controllerkey_proxy(*this), kbd(_kbd
), domain(_domain
)
141 register_queue
<_inverse_proxy
, inverse_bind
>::do_ready(inverse_proxy
, true);
142 register_queue
<_controllerkey_proxy
, controller_key
>::do_ready(controllerkey_proxy
, true);
145 keyboard_mapper::~keyboard_mapper() throw()
147 register_queue
<_inverse_proxy
, inverse_bind
>::do_ready(inverse_proxy
, false);
148 register_queue
<_controllerkey_proxy
, controller_key
>::do_ready(controllerkey_proxy
, false);
151 keyboard_mapper::triplet::triplet(keyboard_modifier_set _mod
, keyboard_modifier_set _mask
, keyboard_key
& _key
,
161 keyboard_mapper::triplet::triplet(keyboard_key
& _key
, unsigned _subkey
)
168 bool keyboard_mapper::triplet::operator<(const struct triplet
& a
) const
170 if((uint64_t)key
< (uint64_t)a
.key
)
172 if((uint64_t)key
> (uint64_t)a
.key
)
174 if(subkey
< a
.subkey
)
176 if(subkey
> a
.subkey
)
178 if(index
&& !a
.index
)
180 if(!index
&& a
.index
)
193 bool keyboard_mapper::triplet::operator==(const struct triplet
& a
) const
199 if(subkey
!= a
.subkey
)
203 if(!(mask
== a
.mask
))
208 key_specifier
keyboard_mapper::triplet::as_keyspec() const throw(std::bad_alloc
)
213 auto s
= key
->get_subkeys();
214 if(s
.size() > subkey
)
215 k
.key
= key
->get_name() + s
[subkey
];
217 k
.key
= key
->get_name();
221 std::list
<key_specifier
> keyboard_mapper::get_bindings() throw(std::bad_alloc
)
223 umutex_class
u(mutex
);
224 std::list
<key_specifier
> r
;
225 for(auto i
: bindings
)
226 r
.push_back(i
.first
.as_keyspec());
230 command_group
& keyboard_mapper::get_command_group() throw()
235 void keyboard_mapper::bind(std::string mod
, std::string modmask
, std::string keyname
, std::string command
)
236 throw(std::bad_alloc
, std::runtime_error
)
242 triplet
t(kbd
, spec
);
243 umutex_class
u(mutex
);
244 if(bindings
.count(t
))
245 throw std::runtime_error("Key is already bound");
246 if(!listening
.count(t
.key
)) {
247 t
.key
->add_listener(*this, false);
248 listening
.insert(t
.key
);
250 std::string old_command
;
251 if(bindings
.count(t
))
252 old_command
= bindings
[t
];
253 bindings
[t
] = command
;
254 change_command(spec
, old_command
, command
);
257 void keyboard_mapper::unbind(std::string mod
, std::string modmask
, std::string keyname
) throw(std::bad_alloc
,
264 triplet
t(kbd
, spec
);
265 umutex_class
u(mutex
);
266 if(!bindings
.count(t
))
267 throw std::runtime_error("Key is not bound");
268 //No harm at leaving listeners listening.
269 std::string old_command
;
270 if(bindings
.count(t
))
271 old_command
= bindings
[t
];
273 change_command(spec
, old_command
, "");
276 std::string
keyboard_mapper::get(const key_specifier
& keyspec
) throw(std::bad_alloc
)
278 triplet
t(kbd
, keyspec
);
279 umutex_class
u(mutex
);
280 if(!bindings
.count(t
))
285 void keyboard_mapper::change_command(const key_specifier
& spec
, const std::string
& old
, const std::string
& newc
)
287 if(old
!= "" && ibinds
.count(old
)) {
288 auto& i
= ibinds
[old
];
290 umutex_class
u2(i
->mutex
);
293 for(auto j
: bindings
)
294 if(j
.second
== i
->cmd
&& j
.first
.as_keyspec() != spec
) {
295 umutex_class
u2(i
->mutex
);
296 i
->specs
.push_back(j
.first
.as_keyspec());
299 if(newc
!= "" && ibinds
.count(newc
)) {
300 auto& i
= ibinds
[newc
];
301 umutex_class
u2(i
->mutex
);
302 i
->specs
.push_back(spec
);
306 void keyboard_mapper::set(const key_specifier
& keyspec
, const std::string
& cmd
) throw(std::bad_alloc
,
309 triplet
t(kbd
, keyspec
);
310 umutex_class
u(mutex
);
311 if(!listening
.count(t
.key
)) {
312 t
.key
->add_listener(*this, false);
313 listening
.insert(t
.key
);
316 if(bindings
.count(t
))
317 oldcmd
= bindings
[t
];
319 change_command(keyspec
, oldcmd
, cmd
);
322 void keyboard_mapper::on_key_event(keyboard_modifier_set
& mods
, keyboard_key
& key
, keyboard_event
& event
)
324 auto mask
= event
.get_change_mask();
327 unsigned k
= mask
& 3;
329 on_key_event_subkey(mods
, key
, i
, k
== 3);
335 void keyboard_mapper::on_key_event_subkey(keyboard_modifier_set
& mods
, keyboard_key
& key
, unsigned skey
,
338 triplet
llow(key
, skey
);
339 triplet
lhigh(key
, skey
+ 1);
340 auto low
= bindings
.lower_bound(llow
);
341 auto high
= bindings
.lower_bound(lhigh
);
342 for(auto i
= low
; i
!= high
; i
++) {
343 if(!mods
.triggers(i
->first
.mod
, i
->first
.mask
))
345 std::string cmd
= fixup_command_polarity(i
->second
, polarity
);
351 keyboard_mapper::triplet::triplet(keyboard
& k
, const key_specifier
& spec
)
353 mod
= keyboard_modifier_set::construct(k
, spec
.mod
);
354 mask
= keyboard_modifier_set::construct(k
, spec
.mask
);
356 throw std::runtime_error("Bad modifiers");
357 auto g
= keymapper_lookup_subkey(k
, spec
.key
, false);
363 std::list
<controller_key
*> keyboard_mapper::get_controllerkeys_kbdkey(keyboard_key
* kbdkey
)
364 throw(std::bad_alloc
)
366 umutex_class
u(mutex
);
367 std::list
<controller_key
*> r
;
368 for(auto i
: ckeys
) {
369 for(unsigned j
= 0;; j
++) {
370 auto k
= i
.second
->get(j
);
373 if(k
.first
== kbdkey
)
374 r
.push_back(i
.second
);
380 inverse_bind::inverse_bind(keyboard_mapper
& _mapper
, const std::string
& _command
, const std::string
& _name
)
381 throw(std::bad_alloc
)
382 : mapper(_mapper
), cmd(_command
), oname(_name
)
384 register_queue
<keyboard_mapper::_inverse_proxy
, inverse_bind
>::do_register(mapper
.inverse_proxy
, cmd
, *this);
387 inverse_bind::~inverse_bind() throw()
389 register_queue
<keyboard_mapper::_inverse_proxy
, inverse_bind
>::do_unregister(mapper
.inverse_proxy
, cmd
);
392 key_specifier
inverse_bind::get(unsigned index
) throw(std::bad_alloc
)
394 umutex_class
u(mutex
);
395 if(index
>= specs
.size())
396 return key_specifier();
400 void inverse_bind::clear(unsigned index
) throw(std::bad_alloc
)
402 key_specifier unbind
;
404 umutex_class
u(mutex
);
405 if(index
>= specs
.size())
407 unbind
= specs
[index
];
410 mapper
.set(unbind
, "");
413 void inverse_bind::append(const key_specifier
& keyspec
) throw(std::bad_alloc
)
415 mapper
.set(keyspec
, cmd
);
418 std::string
inverse_bind::getname() throw(std::bad_alloc
)
423 controller_key::controller_key(keyboard_mapper
& _mapper
, const std::string
& _command
, const std::string
& _name
,
424 bool _axis
) throw(std::bad_alloc
)
425 : mapper(_mapper
), cmd(_command
), oname(_name
)
427 register_queue
<keyboard_mapper::_controllerkey_proxy
, controller_key
>::do_register(mapper
.controllerkey_proxy
,
432 controller_key::~controller_key() throw()
434 register_queue
<keyboard_mapper::_controllerkey_proxy
, controller_key
>::do_unregister(
435 mapper
.controllerkey_proxy
, cmd
);
438 std::pair
<keyboard_key
*, unsigned> controller_key::get(unsigned index
) throw()
440 umutex_class
u(mutex
);
441 if(index
>= keys
.size())
442 return std::make_pair(reinterpret_cast<keyboard_key
*>(NULL
), 0);
446 std::string
controller_key::get_string(unsigned index
) throw(std::bad_alloc
)
451 auto s
= k
.first
->get_subkeys();
452 if(k
.second
>= s
.size() || axis
)
453 return k
.first
->get_name();
454 return k
.first
->get_name() + s
[k
.second
];
457 void controller_key::append(keyboard_key
* _key
, unsigned _subkey
) throw()
459 umutex_class
u(mutex
);
460 //Search for duplicates.
461 std::pair
<keyboard_key
*, unsigned> mkey
= std::make_pair(_key
, _subkey
);
466 _key
->add_listener(*this, axis
);
467 keys
.push_back(mkey
);
470 void controller_key::remove(keyboard_key
* _key
, unsigned _subkey
) throw()
472 umutex_class
u(mutex
);
473 std::pair
<keyboard_key
*, unsigned> mkey
= std::make_pair(_key
, _subkey
);
474 for(auto i
= keys
.begin(); i
!= keys
.end(); i
++) {
476 mkey
.first
->remove_listener(*this);
483 void controller_key::append(const std::string
& _key
) throw(std::bad_alloc
, std::runtime_error
)
485 auto g
= keymapper_lookup_subkey(mapper
.get_keyboard(), _key
, axis
);
486 append(g
.first
, g
.second
);
489 std::pair
<keyboard_key
*, unsigned> keymapper_lookup_subkey(keyboard
& kbd
, const std::string
& name
, bool axis
)
490 throw(std::bad_alloc
, std::runtime_error
)
493 return std::make_pair((keyboard_key
*)NULL
, 0);
494 //Try direct lookup first.
495 keyboard_key
* key
= kbd
.try_lookup_key(name
);
497 return std::make_pair(key
, 0);
498 //Axes only do direct lookup.
500 throw std::runtime_error("Invalid key");
501 std::string prefix
= name
;
502 char letter
= prefix
[prefix
.length() - 1];
503 prefix
= prefix
.substr(0, prefix
.length() - 1);
504 key
= kbd
.try_lookup_key(prefix
);
506 throw std::runtime_error("Invalid key");
507 auto s
= key
->get_subkeys();
508 for(size_t i
= 0; i
< s
.size(); i
++)
509 if(s
[i
].length() > 0 && letter
== s
[i
][0])
510 return std::make_pair(key
, i
);
511 throw std::runtime_error("Invalid key");
514 void controller_key::on_key_event(keyboard_modifier_set
& mods
, keyboard_key
& key
, keyboard_event
& event
)
517 //Axes work specially.
518 mapper
.get_command_group().invoke((stringfmt() << cmd
<< " " << event
.get_state()).str());
521 auto mask
= event
.get_change_mask();
525 unsigned kmask
= (mask
>> (2 * i
.second
)) & 3;
528 cmd2
= keyboard_mapper::fixup_command_polarity(cmd
, kmask
== 3);
530 mapper
.get_command_group().invoke(cmd2
);