1 #include "keymapper.hpp"
10 #include "memorymanip.hpp"
11 #include "command.hpp"
15 function_ptr_command
<tokensplitter
&> bind_key("bind-key", "Bind a (pseudo-)key",
16 "Syntax: bind-key [<mod>/<modmask>] <key> <command>\nBind command to specified key (with specified "
18 [](tokensplitter
& t
) throw(std::bad_alloc
, std::runtime_error
) {
19 std::string mod
, modmask
, keyname
, command
;
20 std::string mod_or_key
= t
;
21 if(mod_or_key
.find_first_of("/") < mod_or_key
.length()) {
23 size_t split
= mod_or_key
.find_first_of("/");
24 mod
= mod_or_key
.substr(0, split
);
25 modmask
= mod_or_key
.substr(split
+ 1);
26 mod_or_key
= static_cast<std::string
>(t
);
29 throw std::runtime_error("Expected optional modifiers and key");
33 throw std::runtime_error("Expected command");
34 keymapper::bind(mod
, modmask
, keyname
, command
);
35 if(mod
!= "" || modmask
!= "")
36 messages
<< mod
<< "/" << modmask
<< " ";
37 messages
<< keyname
<< " bound to '" << command
<< "'" << std::endl
;
41 function_ptr_command
<tokensplitter
&> unbind_key("unbind-key", "Unbind a (pseudo-)key",
42 "Syntax: unbind-key [<mod>/<modmask>] <key>\nUnbind specified key (with specified modifiers)\n",
43 [](tokensplitter
& t
) throw(std::bad_alloc
, std::runtime_error
) {
44 std::string mod
, modmask
, keyname
, command
;
45 std::string mod_or_key
= t
;
46 if(mod_or_key
.find_first_of("/") < mod_or_key
.length()) {
48 size_t split
= mod_or_key
.find_first_of("/");
49 mod
= mod_or_key
.substr(0, split
);
50 modmask
= mod_or_key
.substr(split
+ 1);
51 mod_or_key
= static_cast<std::string
>(t
);
54 throw std::runtime_error("Expected optional modifiers and key");
58 throw std::runtime_error("Unexpected argument");
59 keymapper::unbind(mod
, modmask
, keyname
);
60 if(mod
!= "" || modmask
!= "")
61 messages
<< mod
<< "/" << modmask
<< " ";
62 messages
<< keyname
<< " unbound" << std::endl
;
65 function_ptr_command
<> show_bindings("show-bindings", "Show active bindings",
66 "Syntax: show-bindings\nShow bindings that are currently active.\n",
67 []() throw(std::bad_alloc
, std::runtime_error
) {
68 keymapper::dumpbindings();
72 std::string
fixup_command_polarity(std::string cmd
, bool polarity
) throw(std::bad_alloc
)
76 if(cmd
[0] != '+' && polarity
)
78 if(cmd
[0] == '+' && !polarity
)
85 std::map
<std::string
, modifier
*>* known_modifiers
;
86 std::map
<std::string
, std::string
>* modifier_linkages
;
87 std::map
<std::string
, keygroup
*>* keygroups
;
89 //Returns orig if not linked.
90 const modifier
* get_linked_modifier(const modifier
* orig
)
92 if(!modifier_linkages
|| !modifier_linkages
->count(orig
->name()))
94 std::string l
= (*modifier_linkages
)[orig
->name()];
95 return (*known_modifiers
)[l
];
99 modifier::modifier(const std::string
& name
) throw(std::bad_alloc
)
102 known_modifiers
= new std::map
<std::string
, modifier
*>();
103 (*known_modifiers
)[modname
= name
] = this;
106 modifier::modifier(const std::string
& name
, const std::string
& linkgroup
) throw(std::bad_alloc
)
109 known_modifiers
= new std::map
<std::string
, modifier
*>();
110 if(!modifier_linkages
)
111 modifier_linkages
= new std::map
<std::string
, std::string
>();
112 (*known_modifiers
)[modname
= name
] = this;
113 (*modifier_linkages
)[name
] = linkgroup
;
116 modifier
& modifier::lookup(const std::string
& name
) throw(std::bad_alloc
, std::runtime_error
)
118 if(!known_modifiers
|| !known_modifiers
->count(name
)) {
119 std::ostringstream x
;
120 x
<< "Invalid modifier '" << name
<< "'";
121 throw std::runtime_error(x
.str());
123 return *(*known_modifiers
)[name
];
126 std::string
modifier::name() const throw(std::bad_alloc
)
132 void modifier_set::add(const modifier
& mod
, bool really
) throw(std::bad_alloc
)
138 void modifier_set::remove(const modifier
& mod
, bool really
) throw(std::bad_alloc
)
144 modifier_set
modifier_set::construct(const std::string
& _modifiers
) throw(std::bad_alloc
, std::runtime_error
)
147 std::string modifiers
= _modifiers
;
148 while(modifiers
!= "") {
149 std::string mod
= modifiers
;
151 size_t split
= modifiers
.find_first_of(",");
152 if(split
< modifiers
.length()) {
153 mod
= modifiers
.substr(0, split
);
154 rest
= modifiers
.substr(split
+ 1);
156 set
.add(modifier::lookup(mod
));
162 bool modifier_set::valid(const modifier_set
& set
, const modifier_set
& mask
) throw(std::bad_alloc
)
164 //No element can be together with its linkage group.
165 for(auto i
= set
.set
.begin(); i
!= set
.set
.end(); ++i
) {
166 const modifier
* j
= get_linked_modifier(*i
);
167 if(*i
!= j
&& set
.set
.count(j
))
170 for(auto i
= mask
.set
.begin(); i
!= mask
.set
.end(); ++i
) {
171 const modifier
* j
= get_linked_modifier(*i
);
172 if(*i
!= j
&& mask
.set
.count(j
))
175 //For every element of set, it or its linkage group must be in mask.
176 for(auto i
= set
.set
.begin(); i
!= set
.set
.end(); ++i
) {
177 const modifier
* j
= get_linked_modifier(*i
);
178 if(!mask
.set
.count(*i
) && !mask
.set
.count(j
))
184 bool modifier_set::operator==(const modifier_set
& m
) const throw()
186 for(auto i
= set
.begin(); i
!= set
.end(); ++i
)
189 for(auto i
= m
.set
.begin(); i
!= m
.set
.end(); ++i
)
195 bool modifier_set::triggers(const modifier_set
& set
, const modifier_set
& trigger
, const modifier_set
& mask
)
196 throw(std::bad_alloc
)
198 modifier_set unmet
= trigger
;
200 for(auto i
= set
.set
.begin(); i
!= set
.set
.end(); i
++) {
201 auto linked
= get_linked_modifier(*i
);
202 if(mask
.set
.count(linked
) && trigger
.set
.count(linked
))
203 unmet
.remove(*linked
);
204 if(mask
.set
.count(linked
) && trigger
.set
.count(*i
))
206 if(mask
.set
.count(*i
) && trigger
.set
.count(*i
))
209 return (unmet
== blank
);
212 std::string
keygroup::name() throw(std::bad_alloc
)
218 keygroup::keygroup(const std::string
& name
, enum type t
) throw(std::bad_alloc
)
221 keygroups
= new std::map
<std::string
, keygroup
*>();
222 (*keygroups
)[keyname
= name
] = this;
231 void keygroup::change_type(enum type t
)
237 std::pair
<keygroup
*, unsigned> keygroup::lookup(const std::string
& name
) throw(std::bad_alloc
,
241 throw std::runtime_error("Invalid key");
242 if(keygroups
->count(name
))
243 return std::make_pair((*keygroups
)[name
], 0);
244 std::string prefix
= name
;
245 char letter
= prefix
[prefix
.length() - 1];
246 prefix
= prefix
.substr(0, prefix
.length() - 1);
247 if(!keygroups
->count(prefix
))
248 throw std::runtime_error("Invalid key");
249 keygroup
* g
= (*keygroups
)[prefix
];
253 return std::make_pair(g
, 0);
256 return std::make_pair(g
, 1);
258 return std::make_pair(g
, 2);
260 return std::make_pair(g
, 3);
262 throw std::runtime_error("Invalid key");
266 void keygroup::change_calibration(short left
, short center
, short right
, double tolerance
)
271 cal_tolerance
= tolerance
;
274 double keygroup::compensate(short value
)
276 if(ktype
== KT_HAT
|| ktype
== KT_KEY
|| ktype
== KT_DISABLED
)
277 return value
; //These can't be calibrated.
278 if(value
<= cal_left
)
280 else if(value
>= cal_right
)
282 else if(value
== cal_center
)
284 else if(value
< cal_center
)
285 return (static_cast<double>(value
) - cal_center
) / (static_cast<double>(cal_center
) - cal_left
);
287 return (static_cast<double>(value
) - cal_center
) / (static_cast<double>(cal_right
) - cal_center
);
290 double keygroup::compensate2(double value
)
294 return 0; //Always neutral.
297 return value
; //No mapping.
305 return (1 + value
) / 2;
309 return (1 - value
) / 2;
312 case KT_AXIS_PAIR_INVERSE
:
317 void keygroup::set_position(short pos
, const modifier_set
& modifiers
) throw()
319 double x
= compensate2(compensate(pos
));
321 bool left
, right
, up
, down
;
322 bool oleft
, oright
, oup
, odown
;
333 tmp
= (x
>= cal_tolerance
);
334 run_listeners(modifiers
, 0, true, (!state
&& tmp
), x
);
335 run_listeners(modifiers
, 0, false, (state
&& !tmp
), x
);
339 case KT_AXIS_PAIR_INVERSE
:
340 if(x
<= -cal_tolerance
)
342 else if(x
>= cal_tolerance
)
346 run_listeners(modifiers
, 0, false, state
== 1 && tmp
!= 1, x
);
347 run_listeners(modifiers
, 1, false, state
== 2 && tmp
!= 2, x
);
348 run_listeners(modifiers
, 0, true, tmp
== 1 && state
!= 1, x
);
349 run_listeners(modifiers
, 1, true, tmp
== 2 && state
!= 2, x
);
353 left
= ((pos
& 8) != 0);
354 right
= ((pos
& 2) != 0);
355 up
= ((pos
& 1) != 0);
356 down
= ((pos
& 4) != 0);
357 oleft
= ((state
& 8) != 0);
358 oright
= ((state
& 2) != 0);
359 oup
= ((state
& 1) != 0);
360 odown
= ((state
& 4) != 0);
361 run_listeners(modifiers
, 3, false, oleft
&& !left
, x
);
362 run_listeners(modifiers
, 1, false, oright
&& !right
, x
);
363 run_listeners(modifiers
, 0, false, oup
&& !up
, x
);
364 run_listeners(modifiers
, 2, false, odown
&& !down
, x
);
365 run_listeners(modifiers
, 2, true, !odown
&& down
, x
);
366 run_listeners(modifiers
, 0, true, !oup
&& up
, x
);
367 run_listeners(modifiers
, 1, true, !oright
&& right
, x
);
368 run_listeners(modifiers
, 3, true, !oleft
&& left
, x
);
374 void keygroup::add_key_listener(key_listener
& l
) throw(std::bad_alloc
)
376 listeners
.push_back(&l
);
379 void keygroup::remove_key_listener(key_listener
& l
) throw(std::bad_alloc
)
381 for(auto i
= listeners
.begin(); i
!= listeners
.end(); ++i
)
388 void keygroup::run_listeners(const modifier_set
& modifiers
, unsigned subkey
, bool polarity
, bool really
, double x
)
392 std::string name
= keyname
;
393 if(ktype
== KT_AXIS_PAIR
&& subkey
== 0)
395 if(ktype
== KT_AXIS_PAIR
&& subkey
== 1)
397 if(ktype
== KT_HAT
&& subkey
== 0)
399 if(ktype
== KT_HAT
&& subkey
== 1)
401 if(ktype
== KT_HAT
&& subkey
== 2)
403 if(ktype
== KT_HAT
&& subkey
== 3)
406 exclusive
->key_event(modifiers
, *this, subkey
, polarity
, name
);
409 for(auto i
= listeners
.begin(); i
!= listeners
.end(); ++i
)
410 (*i
)->key_event(modifiers
, *this, subkey
, polarity
, name
);
413 keygroup::key_listener
* keygroup::exclusive
;
415 void keygroup::set_exclusive_key_listener(key_listener
* l
) throw()
424 triple(const std::string
& _a
, const std::string
& _b
, const std::string
& _c
)
433 bool operator==(const triple
& t
) const
435 bool x
= (a
== t
.a
&& b
== t
.b
&& c
== t
.c
);
438 bool operator<(const triple
& t
) const
440 bool x
= (a
< t
.a
|| (a
== t
.a
&& b
< t
.b
) || (a
== t
.a
&& b
== t
.b
&& c
< t
.c
));
444 struct keybind_data
: public keygroup::key_listener
447 modifier_set modmask
;
451 void key_event(const modifier_set
& modifiers
, keygroup
& keygroup
, unsigned subkey
, bool polarity
,
452 const std::string
& name
)
454 if(!modifier_set::triggers(modifiers
, mod
, modmask
))
456 std::string cmd
= fixup_command_polarity(command
, polarity
);
459 command::invokeC(cmd
);
463 std::map
<triple
, keybind_data
> keybindings
;
466 void keymapper::bind(std::string mod
, std::string modmask
, std::string keyname
, std::string command
)
467 throw(std::bad_alloc
, std::runtime_error
)
469 triple
k(mod
, modmask
, keyname
);
470 modifier_set _mod
= modifier_set::construct(mod
);
471 modifier_set _modmask
= modifier_set::construct(modmask
);
472 if(!modifier_set::valid(_mod
, _modmask
))
473 throw std::runtime_error("Invalid modifiers");
474 auto g
= keygroup::lookup(keyname
);
475 if(!keybindings
.count(k
)) {
476 keybindings
[k
].mod
= _mod
;
477 keybindings
[k
].modmask
= _modmask
;
478 keybindings
[k
].group
= g
.first
;
479 keybindings
[k
].subkey
= g
.second
;
480 g
.first
->add_key_listener(keybindings
[k
]);
482 keybindings
[k
].command
= command
;
484 void keymapper::unbind(std::string mod
, std::string modmask
, std::string keyname
) throw(std::bad_alloc
,
487 triple
k(mod
, modmask
, keyname
);
488 if(!keybindings
.count(k
))
489 throw std::runtime_error("Key is not bound");
490 keybindings
[k
].group
->remove_key_listener(keybindings
[k
]);
491 keybindings
.erase(k
);
494 void keymapper::dumpbindings() throw(std::bad_alloc
)
496 for(auto i
= keybindings
.begin(); i
!= keybindings
.end(); ++i
) {
497 messages
<< "bind-key ";
498 if(i
->first
.a
!= "" || i
->first
.b
!= "")
499 messages
<< i
->first
.a
<< "/" << i
->first
.b
<< " ";
500 messages
<< i
->first
.c
<< std::endl
;