41 , bindCmd (commandController_, *this, false)
42 , bindDefaultCmd (commandController_, *this, true)
43 , unbindCmd (commandController_, *this, false)
44 , unbindDefaultCmd(commandController_, *this, true)
45 , activateCmd (commandController_)
46 , deactivateCmd (commandController_)
47 , commandController(commandController_)
48 , eventDistributor(eventDistributor_)
50 initDefaultBindings();
100 void HotKey::initDefaultBindings()
106 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
108 "screenshot -guess-name"));
109 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
112 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
114 "toggle fastforward"));
115 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
118 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
121 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
123 "toggle fullscreen"));
124 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
129 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_PRINT),
130 "screenshot -guess-name"));
131 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_PAUSE),
133 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_F9),
134 "toggle fastforward"));
135 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_F10),
137 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_F11),
138 "toggle fullscreen"));
139 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_F12),
141 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
144 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
147 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
149 "toggle fullscreen"));
151 bindDefault(HotKeyInfo(Event::create<KeyDownEvent>(
Keys::K_BACK),
152 "quitmenu::quit_menu"));
156 static Event createEvent(
const TclObject& obj, Interpreter& interp)
166 throw CommandException(
"Unsupported event type");
170 static Event createEvent(std::string_view str, Interpreter& interp)
172 return createEvent(TclObject(str), interp);
186 std::string(cmd),
repeat, event));
200 return event == info.
event;
205 static bool contains(
auto&& range,
const Event& event)
211 static void erase(std::vector<T>& v,
const Event& event)
223 set.push_back(event);
227 template<
typename HotKeyInfo>
231 *it = std::forward<HotKeyInfo>(info);
233 map.push_back(std::forward<HotKeyInfo>(info));
237 void HotKey::bind(HotKeyInfo&& info)
239 erase(unboundKeys, info.event);
240 erase(defaultMap, info.event);
241 insert(boundKeys, info.event);
242 insert(cmdMap, std::move(info));
245 void HotKey::unbind(
const Event& event)
248 it1 ==
end(boundKeys)) {
250 insert(unboundKeys, event);
256 erase(defaultMap, event);
257 erase(cmdMap, event);
260 void HotKey::bindDefault(HotKeyInfo&& info)
262 if (!contains( boundKeys, info.event) &&
263 !contains(unboundKeys, info.event)) {
265 insert(cmdMap, info);
267 insert(defaultMap, std::move(info));
270 void HotKey::unbindDefault(
const Event& event)
272 if (!contains( boundKeys, event) &&
273 !contains(unboundKeys, event)) {
275 erase(cmdMap, event);
277 erase(defaultMap, event);
280 void HotKey::bindLayer(HotKeyInfo&& info,
const string& layer)
282 insert(layerMap[layer], std::move(info));
285 void HotKey::unbindLayer(
const Event& event,
const string& layer)
287 erase(layerMap[layer], event);
290 void HotKey::unbindFullLayer(
const string& layer)
292 layerMap.erase(layer);
295 void HotKey::activateLayer(std::string layer,
bool blocking)
301 activeLayers.push_back({std::move(layer), blocking});
304 void HotKey::deactivateLayer(std::string_view layer)
309 it != activeLayers.rend()) {
311 activeLayers.erase((it + 1).base());
315 static HotKey::BindMap::const_iterator findMatch(
319 return matches(p.event, event);
323 void HotKey::executeRT()
325 if (lastEvent) executeEvent(lastEvent);
328 int HotKey::signalEvent(
const Event& event) noexcept
330 if (lastEvent.getPtr() != event.getPtr()) {
343 return executeEvent(event);
346 int HotKey::executeEvent(
const Event& event)
349 bool blocking =
false;
351 auto& cmap = layerMap[info.layer];
352 if (
auto it = findMatch(cmap, event); it !=
end(cmap)) {
353 executeBinding(event, *it);
358 blocking = info.blocking;
363 if (
auto it = findMatch(cmdMap, event); it !=
end(cmdMap)) {
364 executeBinding(event, *it);
373 void HotKey::executeBinding(
const Event& event,
const HotKeyInfo& info)
389 TclObject command(info.command);
390 if (info.passEvent) {
395 command.addListElement(
toTclList(event));
400 }
catch (CommandException&
e) {
402 "Error executing hot key command: ",
e.getMessage());
406 void HotKey::startRepeat(
const Event& event)
417 static constexpr
unsigned PERIOD = 30;
419 unsigned delay = (lastEvent ? PERIOD : DELAY) * 1000;
424 void HotKey::stopRepeat()
433 static constexpr std::string_view getBindCmdName(
bool defaultCmd)
435 return defaultCmd ?
"bind_default" :
"bind";
438 HotKey::BindCmd::BindCmd(CommandController& commandController_, HotKey& hotKey_,
440 : Command(commandController_, getBindCmdName(defaultCmd_))
442 , defaultCmd(defaultCmd_)
446 static string formatBinding(
const HotKey::HotKeyInfo& info)
448 return strCat(
toString(info.event), (info.repeat ?
" [repeat]" :
""),
449 (info.passEvent ?
" [event]" :
""),
": ", info.command,
'\n');
452 void HotKey::BindCmd::execute(std::span<const TclObject> tokens, TclObject& result)
457 bool passEvent =
false;
458 ArgsInfo parserInfo[] = {
464 auto arguments =
parseTclArgs(getInterpreter(), tokens.subspan<1>(), parserInfo);
465 if (defaultCmd && !layer.empty()) {
466 throw CommandException(
"Layers are not supported for default bindings");
469 auto& cMap = defaultCmd
471 : layer.empty() ? hotKey.cmdMap
472 : hotKey.layerMap[layer];
475 for (
const auto& [layerName, bindings] : hotKey.layerMap) {
478 if (!bindings.empty()) {
479 result.addListElement(layerName);
485 switch (arguments.size()) {
489 for (
auto& p : cMap) {
490 r += formatBinding(p);
498 EqualEvent(createEvent(arguments[0], getInterpreter())));
499 if (it ==
end(cMap)) {
500 throw CommandException(
"Key not bound");
502 result = formatBinding(*it);
507 string command(arguments[1].getString());
508 for (
const auto& arg :
view::drop(arguments, 2)) {
509 strAppend(command,
' ', arg.getString());
511 HotKey::HotKeyInfo info(
512 createEvent(arguments[0], getInterpreter()),
513 command,
repeat, passEvent);
515 hotKey.bindDefault(std::move(info));
516 }
else if (layer.empty()) {
517 hotKey.bind(std::move(info));
519 hotKey.bindLayer(std::move(info), layer);
525 string HotKey::BindCmd::help(std::span<const TclObject> )
const
527 auto cmd = getBindCmdName(defaultCmd);
529 cmd,
" : show all bounded keys\n",
530 cmd,
" <key> : show binding for this key\n",
531 cmd,
" <key> [-repeat] [-event] <cmd> : bind key to command, optionally "
532 "repeat command while key remains pressed and also optionally "
533 "give back the event as argument (a list) to <cmd>\n"
534 "These 3 take an optional '-layer <layername>' option, "
535 "see activate_input_layer.\n",
536 cmd,
" -layers : show a list of layers with bound keys\n");
542 static constexpr std::string_view getUnbindCmdName(
bool defaultCmd)
544 return defaultCmd ?
"unbind_default" :
"unbind";
547 HotKey::UnbindCmd::UnbindCmd(CommandController& commandController_,
548 HotKey& hotKey_,
bool defaultCmd_)
549 : Command(commandController_, getUnbindCmdName(defaultCmd_))
551 , defaultCmd(defaultCmd_)
555 void HotKey::UnbindCmd::execute(std::span<const TclObject> tokens, TclObject& )
558 ArgsInfo info[] = {
valueArg(
"-layer", layer) };
559 auto arguments =
parseTclArgs(getInterpreter(), tokens.subspan<1>(), info);
560 if (defaultCmd && !layer.empty()) {
561 throw CommandException(
"Layers are not supported for default bindings");
564 if ((arguments.size() > 1) || (layer.empty() && (arguments.size() != 1))) {
569 if (arguments.size() == 1) {
570 event = createEvent(arguments[0], getInterpreter());
575 hotKey.unbindDefault(event);
576 }
else if (layer.empty()) {
578 hotKey.unbind(event);
581 hotKey.unbindLayer(event, layer);
583 hotKey.unbindFullLayer(layer);
587 string HotKey::UnbindCmd::help(std::span<const TclObject> )
const
589 auto cmd = getUnbindCmdName(defaultCmd);
591 cmd,
" <key> : unbind this key\n",
592 cmd,
" -layer <layername> <key> : unbind key in a specific layer\n",
593 cmd,
" -layer <layername> : unbind all keys in this layer\n");
599 HotKey::ActivateCmd::ActivateCmd(CommandController& commandController_)
600 : Command(commandController_,
"activate_input_layer")
604 void HotKey::ActivateCmd::execute(std::span<const TclObject> tokens, TclObject& result)
606 bool blocking =
false;
607 ArgsInfo info[] = {
flagArg(
"-blocking", blocking) };
608 auto args =
parseTclArgs(getInterpreter(), tokens.subspan(1), info);
610 auto& hotKey =
OUTER(HotKey, activateCmd);
611 switch (args.size()) {
615 r += layerInfo.layer;
616 if (layerInfo.blocking) {
625 std::string_view layer = args[0].getString();
626 hotKey.activateLayer(
string(layer), blocking);
634 string HotKey::ActivateCmd::help(std::span<const TclObject> )
const
636 return "activate_input_layer "
637 ": show list of active layers (most recent on top)\n"
638 "activate_input_layer [-blocking] <layername> "
639 ": activate new layer, optionally in blocking mode\n";
645 HotKey::DeactivateCmd::DeactivateCmd(CommandController& commandController_)
646 : Command(commandController_,
"deactivate_input_layer")
650 void HotKey::DeactivateCmd::execute(std::span<const TclObject> tokens, TclObject& )
652 checkNumArgs(tokens, 2,
"layer");
653 auto& hotKey =
OUTER(HotKey, deactivateCmd);
654 hotKey.deactivateLayer(tokens[1].getString());
657 string HotKey::DeactivateCmd::help(std::span<const TclObject> )
const
659 return "deactivate_input_layer <layername> : deactivate the given input layer";
void printWarning(std::string_view message)
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
Interpreter & getInterpreter() override
CliComm & getCliComm() override
HotKey(RTScheduler &rtScheduler, GlobalCommandController &commandController, EventDistributor &eventDistributor)
void loadUnbind(std::string_view key)
std::vector< HotKeyInfo > BindMap
void loadBind(std::string_view key, std::string_view cmd, bool repeat, bool event)
std::vector< Event > KeySet
void scheduleRT(uint64_t delta)
KeyCode combine(KeyCode key, KeyCode modifier)
Convenience method to create key combinations (hides ugly casts).
This file implemented 3 utility functions:
bool isRepeatStopper(const Event &self, const Event &other)
Should 'bind -repeat' be stopped by 'other' event.
bool matches(const Event &self, const Event &other)
Does this event 'match' the given event.
ArgsInfo valueArg(std::string_view name, T &value)
std::vector< TclObject > parseTclArgs(Interpreter &interp, std::span< const TclObject > inArgs, std::span< const ArgsInfo > table)
constexpr bool META_HOT_KEYS
TclObject toTclList(const Event &event)
Similar to toString(), but retains the structure of the event.
EventType getType(const Event &event)
ArgsInfo flagArg(std::string_view name, bool &flag)
std::string toString(const Event &event)
Get a string representation of this event.
bool any_of(InputRange &&range, UnaryPredicate pred)
auto find_if(InputRange &&range, UnaryPredicate pred)
auto find(InputRange &&range, const T &value)
constexpr auto reverse(Range &&range)
constexpr auto drop(Range &&range, size_t n)
#define OUTER(type, member)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
std::string strCat(Ts &&...ts)
void strAppend(std::string &result, Ts &&...ts)
EqualEvent(const Event &event_)
bool operator()(const HotKey::HotKeyInfo &info) const
bool operator()(const Event &e) const
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto end(const zstring_view &x)