Skip to content

Commit 04fc2e7

Browse files
author
houmaster
committed
On mismatch forward only beginning of sequence
1 parent 10c0efb commit 04fc2e7

File tree

4 files changed

+86
-27
lines changed

4 files changed

+86
-27
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ For advanced application it is good to know how the mapping is applied:
116116
* All key strokes are intercepted and appended to a key sequence.
117117
* 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).
118118
* When an input expression matches, the key sequence is cleared and the mapped expression is output.
119-
* When no input expression matches, the key sequence is forwarded unmodified.
119+
* As long as the key sequence can not match any input expression, its first stroke is removed and forwarded as output.
120120
* Keys which already matched but are still physically pressed participate in expression matching as an optional prefix to the key sequence.
121121

122122
Building

src/runtime/Stage.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ namespace {
2626
std::sort(begin(override_set), end(override_set));
2727
return std::move(override_sets);
2828
}
29+
30+
bool has_non_optional(const KeySequence& sequence) {
31+
return std::find_if(begin(sequence), end(sequence),
32+
[](const KeyEvent& e) {
33+
return (e.state == KeyState::Up || e.state == KeyState::Down);
34+
}) != end(sequence);
35+
}
2936
} // namespace
3037

3138
bool operator<(const MappingOverride& a, int mapping_index) {
@@ -88,8 +95,11 @@ KeySequence Stage::apply_input(const KeyEvent event) {
8895
}
8996
}
9097

91-
if (!m_sequence.empty()) {
92-
// find first mapping which matches sequence
98+
for (auto& output : m_output_down)
99+
output.suppressed = false;
100+
101+
while (has_non_optional(m_sequence)) {
102+
// find first mapping which matches or might match sequence
93103
for (const auto& mapping : m_mappings) {
94104
const auto result = m_match(mapping.input, m_sequence);
95105

@@ -106,9 +116,8 @@ KeySequence Stage::apply_input(const KeyEvent event) {
106116
return std::move(m_output_buffer);
107117
}
108118
}
109-
// when no match was found, forward sequence to output
110-
apply_sequence();
111-
finish_sequence();
119+
// when no match was found, forward beginning of sequence
120+
forward_from_sequence();
112121
}
113122
return std::move(m_output_buffer);
114123
}
@@ -158,12 +167,34 @@ void Stage::apply_output(const KeySequence& expression) {
158167
update_output(event, m_sequence.back().key);
159168
}
160169

161-
void Stage::apply_sequence() {
162-
for (const auto& event : m_sequence)
163-
if (event.state == KeyState::Down)
164-
update_output(event, event.key);
165-
else if (event.state == KeyState::Up)
170+
void Stage::forward_from_sequence() {
171+
for (auto it = begin(m_sequence); it != end(m_sequence); ++it) {
172+
auto& event = *it;
173+
if (event.state == KeyState::Down || event.state == KeyState::DownMatched) {
174+
const auto up = std::find(it, end(m_sequence),
175+
KeyEvent{ event.key, KeyState::Up });
176+
if (up != end(m_sequence)) {
177+
// erase Down and Up
178+
update_output(event, event.key);
179+
release_triggered(event.key);
180+
m_sequence.erase(up);
181+
m_sequence.erase(it);
182+
return;
183+
}
184+
else if (event.state == KeyState::Down) {
185+
// no Up yet, convert to DownMatched
186+
update_output(event, event.key);
187+
event.state = KeyState::DownMatched;
188+
return;
189+
}
190+
}
191+
else if (event.state == KeyState::Up) {
192+
// remove remaining Up
166193
release_triggered(event.key);
194+
m_sequence.erase(it);
195+
return;
196+
}
197+
}
167198
}
168199

169200
void Stage::update_output(const KeyEvent& event, KeyCode trigger) {
@@ -210,7 +241,4 @@ void Stage::finish_sequence() {
210241
}
211242
it = m_sequence.erase(it);
212243
}
213-
214-
for (auto& output : m_output_down)
215-
output.suppressed = false;
216244
}

src/runtime/Stage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Stage {
3030
void release_triggered(KeyCode key);
3131
void reapply_temporarily_released();
3232
const KeySequence& get_output(const Mapping& mapping) const;
33-
void apply_sequence();
33+
void forward_from_sequence();
3434
void apply_output(const KeySequence& expression);
3535
void update_output(const KeyEvent& event, KeyCode trigger);
3636
void finish_sequence();

src/test/test3_Stage.cpp

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -135,23 +135,20 @@ TEST_CASE("Sequence", "[Stage]") {
135135
REQUIRE(apply_input(stage, "-X") == "-X");
136136
REQUIRE(format_sequence(stage.sequence()) == "");
137137

138-
// M =>
138+
// M M R => M A
139139
REQUIRE(apply_input(stage, "+M") == "");
140140
REQUIRE(apply_input(stage, "-M") == "");
141-
142-
// M => M M
143-
REQUIRE(apply_input(stage, "+M") == "+M -M +M");
144-
REQUIRE(format_sequence(stage.sequence()) == "#M");
145-
REQUIRE(apply_input(stage, "-M") == "-M");
146-
REQUIRE(format_sequence(stage.sequence()) == "");
147-
148-
// +M R => A
149-
REQUIRE(apply_input(stage, "+M") == "");
141+
REQUIRE(format_sequence(stage.sequence()) == "+M -M");
142+
REQUIRE(apply_input(stage, "+M") == "+M -M");
143+
REQUIRE(format_sequence(stage.sequence()) == "+M");
144+
REQUIRE(apply_input(stage, "-M") == "");
145+
REQUIRE(format_sequence(stage.sequence()) == "+M -M");
150146
REQUIRE(apply_input(stage, "+R") == "+A");
151147
REQUIRE(apply_input(stage, "-R") == "-A");
152-
REQUIRE(format_sequence(stage.sequence()) == "#M");
148+
REQUIRE(format_sequence(stage.sequence()) == "");
153149

154-
// S => B
150+
// +M S => B
151+
REQUIRE(apply_input(stage, "+M") == "");
155152
REQUIRE(apply_input(stage, "+S") == "+B");
156153
REQUIRE(apply_input(stage, "-S") == "-B");
157154
REQUIRE(apply_input(stage, "-M") == "");
@@ -500,3 +497,37 @@ TEST_CASE("Complex modifier - unordered", "[Stage]") {
500497
}
501498

502499
//--------------------------------------------------------------------
500+
501+
TEST_CASE("Might match, then no match or match", "[Stage]") {
502+
auto config = R"(
503+
D >> 0
504+
A{B} >> 1
505+
B >> 2
506+
C >> 3
507+
)";
508+
Stage stage = create_stage(config);
509+
510+
REQUIRE(apply_input(stage, "+A") == "");
511+
REQUIRE(apply_input(stage, "-A") == "+A -A");
512+
513+
REQUIRE(apply_input(stage, "+A") == "");
514+
REQUIRE(apply_input(stage, "+X") == "+A +X");
515+
REQUIRE(apply_input(stage, "-A") == "-A");
516+
517+
REQUIRE(apply_input(stage, "+A") == "");
518+
REQUIRE(apply_input(stage, "+D") == "+A +0");
519+
REQUIRE(apply_input(stage, "-D") == "-0");
520+
REQUIRE(apply_input(stage, "-A") == "-A");
521+
522+
REQUIRE(apply_input(stage, "+A") == "");
523+
REQUIRE(apply_input(stage, "+C") == "+A +3");
524+
REQUIRE(apply_input(stage, "-C") == "-3");
525+
REQUIRE(apply_input(stage, "-A") == "-A");
526+
527+
REQUIRE(apply_input(stage, "+A") == "");
528+
REQUIRE(apply_input(stage, "+B") == "+1");
529+
REQUIRE(apply_input(stage, "-B") == "-1");
530+
REQUIRE(apply_input(stage, "-A") == "");
531+
}
532+
533+
//--------------------------------------------------------------------

0 commit comments

Comments
 (0)