#include "seqmatcher.h" #include #include SeqMatcher::SeqMatcher(Display *dpy) : dpy{dpy} {} SeqMatcher::SeqMatcher(Display *dpy, std::vector seqs) : dpy{dpy} { for (const auto &seq : seqs) addSequence(seq.syms, seq.callback); } void SeqMatcher::addSequence(const std::vector &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(current->v)) { throw std::logic_error("Overlapping key sequences (second is longer)"); } else { if (!std::holds_alternative(current->v)) { current->v.emplace(); } NodeMap &map = std::get(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()).first->second.get(); } } } if (auto *map = std::get_if(¤t->v)) { if (!map->empty()) { throw std::logic_error("Overlapping key sequences (second is shorter)"); } } if (std::holds_alternative(current->v)) { throw std::logic_error("Overlapping key sequences (equally long)"); } current->v.emplace(callback); } std::optional SeqMatcher::observe(const XKeyEvent &ev) { auto *map = std::get_if(&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(&curNode->v)) { // Sequence completed reset(); return *cb; } // Need more keys return std::nullopt; } void SeqMatcher::reset() { curNode = &rootNode; }