Skip to content

Commit

Permalink
On mismatch forward only beginning of sequence
Browse files Browse the repository at this point in the history
  • Loading branch information
houmaster committed Apr 22, 2019
1 parent 10c0efb commit 04fc2e7
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 27 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ For advanced application it is good to know how the mapping is applied:
* All key strokes are intercepted and appended to a key sequence.
* On every key stroke the key sequence is matched with all input expressions in consecutive order, until an expression matches or might match (when more strokes follow).
* When an input expression matches, the key sequence is cleared and the mapped expression is output.
* When no input expression matches, the key sequence is forwarded unmodified.
* As long as the key sequence can not match any input expression, its first stroke is removed and forwarded as output.
* Keys which already matched but are still physically pressed participate in expression matching as an optional prefix to the key sequence.

Building
Expand Down
54 changes: 41 additions & 13 deletions src/runtime/Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ namespace {
std::sort(begin(override_set), end(override_set));
return std::move(override_sets);
}

bool has_non_optional(const KeySequence& sequence) {
return std::find_if(begin(sequence), end(sequence),
[](const KeyEvent& e) {
return (e.state == KeyState::Up || e.state == KeyState::Down);
}) != end(sequence);
}
} // namespace

bool operator<(const MappingOverride& a, int mapping_index) {
Expand Down Expand Up @@ -88,8 +95,11 @@ KeySequence Stage::apply_input(const KeyEvent event) {
}
}

if (!m_sequence.empty()) {
// find first mapping which matches sequence
for (auto& output : m_output_down)
output.suppressed = false;

while (has_non_optional(m_sequence)) {
// find first mapping which matches or might match sequence
for (const auto& mapping : m_mappings) {
const auto result = m_match(mapping.input, m_sequence);

Expand All @@ -106,9 +116,8 @@ KeySequence Stage::apply_input(const KeyEvent event) {
return std::move(m_output_buffer);
}
}
// when no match was found, forward sequence to output
apply_sequence();
finish_sequence();
// when no match was found, forward beginning of sequence
forward_from_sequence();
}
return std::move(m_output_buffer);
}
Expand Down Expand Up @@ -158,12 +167,34 @@ void Stage::apply_output(const KeySequence& expression) {
update_output(event, m_sequence.back().key);
}

void Stage::apply_sequence() {
for (const auto& event : m_sequence)
if (event.state == KeyState::Down)
update_output(event, event.key);
else if (event.state == KeyState::Up)
void Stage::forward_from_sequence() {
for (auto it = begin(m_sequence); it != end(m_sequence); ++it) {
auto& event = *it;
if (event.state == KeyState::Down || event.state == KeyState::DownMatched) {
const auto up = std::find(it, end(m_sequence),
KeyEvent{ event.key, KeyState::Up });
if (up != end(m_sequence)) {
// erase Down and Up
update_output(event, event.key);
release_triggered(event.key);
m_sequence.erase(up);
m_sequence.erase(it);
return;
}
else if (event.state == KeyState::Down) {
// no Up yet, convert to DownMatched
update_output(event, event.key);
event.state = KeyState::DownMatched;
return;
}
}
else if (event.state == KeyState::Up) {
// remove remaining Up
release_triggered(event.key);
m_sequence.erase(it);
return;
}
}
}

void Stage::update_output(const KeyEvent& event, KeyCode trigger) {
Expand Down Expand Up @@ -210,7 +241,4 @@ void Stage::finish_sequence() {
}
it = m_sequence.erase(it);
}

for (auto& output : m_output_down)
output.suppressed = false;
}
2 changes: 1 addition & 1 deletion src/runtime/Stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Stage {
void release_triggered(KeyCode key);
void reapply_temporarily_released();
const KeySequence& get_output(const Mapping& mapping) const;
void apply_sequence();
void forward_from_sequence();
void apply_output(const KeySequence& expression);
void update_output(const KeyEvent& event, KeyCode trigger);
void finish_sequence();
Expand Down
55 changes: 43 additions & 12 deletions src/test/test3_Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,23 +135,20 @@ TEST_CASE("Sequence", "[Stage]") {
REQUIRE(apply_input(stage, "-X") == "-X");
REQUIRE(format_sequence(stage.sequence()) == "");

// M =>
// M M R => M A
REQUIRE(apply_input(stage, "+M") == "");
REQUIRE(apply_input(stage, "-M") == "");

// M => M M
REQUIRE(apply_input(stage, "+M") == "+M -M +M");
REQUIRE(format_sequence(stage.sequence()) == "#M");
REQUIRE(apply_input(stage, "-M") == "-M");
REQUIRE(format_sequence(stage.sequence()) == "");

// +M R => A
REQUIRE(apply_input(stage, "+M") == "");
REQUIRE(format_sequence(stage.sequence()) == "+M -M");
REQUIRE(apply_input(stage, "+M") == "+M -M");
REQUIRE(format_sequence(stage.sequence()) == "+M");
REQUIRE(apply_input(stage, "-M") == "");
REQUIRE(format_sequence(stage.sequence()) == "+M -M");
REQUIRE(apply_input(stage, "+R") == "+A");
REQUIRE(apply_input(stage, "-R") == "-A");
REQUIRE(format_sequence(stage.sequence()) == "#M");
REQUIRE(format_sequence(stage.sequence()) == "");

// S => B
// +M S => B
REQUIRE(apply_input(stage, "+M") == "");
REQUIRE(apply_input(stage, "+S") == "+B");
REQUIRE(apply_input(stage, "-S") == "-B");
REQUIRE(apply_input(stage, "-M") == "");
Expand Down Expand Up @@ -500,3 +497,37 @@ TEST_CASE("Complex modifier - unordered", "[Stage]") {
}

//--------------------------------------------------------------------

TEST_CASE("Might match, then no match or match", "[Stage]") {
auto config = R"(
D >> 0
A{B} >> 1
B >> 2
C >> 3
)";
Stage stage = create_stage(config);

REQUIRE(apply_input(stage, "+A") == "");
REQUIRE(apply_input(stage, "-A") == "+A -A");

REQUIRE(apply_input(stage, "+A") == "");
REQUIRE(apply_input(stage, "+X") == "+A +X");
REQUIRE(apply_input(stage, "-A") == "-A");

REQUIRE(apply_input(stage, "+A") == "");
REQUIRE(apply_input(stage, "+D") == "+A +0");
REQUIRE(apply_input(stage, "-D") == "-0");
REQUIRE(apply_input(stage, "-A") == "-A");

REQUIRE(apply_input(stage, "+A") == "");
REQUIRE(apply_input(stage, "+C") == "+A +3");
REQUIRE(apply_input(stage, "-C") == "-3");
REQUIRE(apply_input(stage, "-A") == "-A");

REQUIRE(apply_input(stage, "+A") == "");
REQUIRE(apply_input(stage, "+B") == "+1");
REQUIRE(apply_input(stage, "-B") == "-1");
REQUIRE(apply_input(stage, "-A") == "");
}

//--------------------------------------------------------------------

0 comments on commit 04fc2e7

Please sign in to comment.