diff options
Diffstat (limited to 'seqmatcher.cpp')
-rw-r--r-- | seqmatcher.cpp | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/seqmatcher.cpp b/seqmatcher.cpp new file mode 100644 index 0000000..f0abedc --- /dev/null +++ b/seqmatcher.cpp @@ -0,0 +1,72 @@ +#include "seqmatcher.h" +#include <cassert> + + +SeqMatcher::SeqMatcher(Display *dpy) : dpy{dpy} {} + +SeqMatcher::SeqMatcher(Display *dpy, std::vector<SymSequence> seqs) + : dpy{dpy} { + for (const auto &seq : seqs) addSequence(seq.syms, seq.callback); +} + +void SeqMatcher::addSequence(const std::vector<x::Keysym> &syms, Callback callback) { + if (syms.empty()) { + throw std::logic_error("Cannot register empty key sequence"); + } + + Node *current = &rootNode; + for (x::Keysym sym : syms) { + if (std::holds_alternative<Callback>(current->v)) { + throw std::logic_error("Overlapping key sequences (second is longer)"); + } else { + if (!std::holds_alternative<NodeMap>(current->v)) { + current->v.emplace<NodeMap>(); + } + NodeMap &map = std::get<NodeMap>(current->v); + x::Keycode code = sym.toCode(dpy); + auto it = map.find(code); + if (it != map.end()) { + current = it->second.get(); + } else { + current = map.emplace(sym.toCode(dpy), std::make_unique<Node>()).first->second.get(); + } + } + } + + if (auto *map = std::get_if<NodeMap>(¤t->v)) { + if (!map->empty()) { + throw std::logic_error("Overlapping key sequences (second is shorter)"); + } + } + if (std::holds_alternative<Callback>(current->v)) { + throw std::logic_error("Overlapping key sequences (equally long)"); + } + current->v.emplace<Callback>(callback); +} + +std::optional<SeqMatcher::Callback> SeqMatcher::observe(const XKeyEvent &ev) { + auto *map = std::get_if<NodeMap>(&curNode->v); + assert(map); + + auto it = map->find(x::Keycode{ev.keycode}); + if (it == map->end()) { + // Sequence not found + reset(); + return [dpy = dpy]() { x::bel(dpy); }; + } + + curNode = it->second.get(); + + if (auto *cb = std::get_if<Callback>(&curNode->v)) { + // Sequence completed + reset(); + return *cb; + } + + // Need more keys + return std::nullopt; +} + +void SeqMatcher::reset() { + curNode = &rootNode; +} |