Skip to content

Commit

Permalink
Improved not-timeout with modifier. e.g "A{B{!500ms}} >> C"
Browse files Browse the repository at this point in the history
  • Loading branch information
houmain committed Jul 4, 2024
1 parent 7c2b7b9 commit 8f58e25
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 23 deletions.
27 changes: 14 additions & 13 deletions src/config/ParseKeySequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,19 @@ void ParseKeySequence::release_pressed_keys(size_t keep_keys_pressed) {
}
}

void ParseKeySequence::sync_after_not_timeouts() {
for (auto i = size_t{ }; i < m_sequence.size(); ++i)
void ParseKeySequence::sync_after_not_timeout() {
// find UpAsyncs after last not-timeout and append an Up for each
const auto last = static_cast<int>(m_sequence.size()) - 1;
for (auto i = last; i >= 0; --i) {
if (is_not_timeout(m_sequence[i])) {
// get number of async Ups
auto n = 0;
for (auto j = i + 1; j < m_sequence.size() &&
m_sequence[j].state == KeyState::UpAsync; ++j)
++n;
// insert a sync Up for each
for (auto j = 0; j < n; ++j)
m_sequence.insert(std::next(m_sequence.begin(), i + 1 + n),
KeyEvent(m_sequence[i + j + 1].key, KeyState::Up));
for (auto j = i + 1; j <= last; ++j)
m_sequence.emplace_back(m_sequence[j].key, KeyState::Up);
break;
}
else if (m_sequence[i].state != KeyState::UpAsync) {
break;
}
}
}

bool ParseKeySequence::all_pressed_at_once() const {
Expand Down Expand Up @@ -338,7 +338,7 @@ void ParseKeySequence::parse(It it, const It end) {
else if (skip(&it, end, "{")) {
// begin modified-group
if (in_together_group)
throw ParseError("Unexpected '('");
throw ParseError("Unexpected '{'");
m_keys_pressed_before_modifier_group.push_back(m_pressed_keys.size());
flush_key_buffer(false);
if (m_pressed_keys.empty())
Expand All @@ -355,6 +355,8 @@ void ParseKeySequence::parse(It it, const It end) {
release_pressed_keys(m_keys_pressed_before_modifier_group.back());
m_keys_pressed_before_modifier_group.pop_back();
--in_modified_group;
if (m_is_input)
sync_after_not_timeout();
}
else if (skip(&it, end, "#") || skip(&it, end, ";")) {
flush_key_buffer(true);
Expand Down Expand Up @@ -385,7 +387,6 @@ void ParseKeySequence::parse(It it, const It end) {
throw ParseError("Expected '}'");

if (m_is_input) {
sync_after_not_timeouts();
if (is_no_might_match)
remove_all_from_end(KeyState::UpAsync);
}
Expand Down
2 changes: 1 addition & 1 deletion src/config/ParseKeySequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ParseKeySequence {
bool remove_from_pressed_keys(Key key);
void flush_key_buffer(bool up_immediately);
void release_pressed_keys(size_t keep_keys_pressed = 0);
void sync_after_not_timeouts();
void sync_after_not_timeout();
bool all_pressed_at_once() const;
void remove_all_from_end(KeyState state);
void check_ContextActive_usage();
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,10 @@ void Stage::release_triggered(Key key, int context_index) {
m_output_buffer.push_back({ k.key, KeyState::Up });
});
m_output_down.erase(it, end(m_output_down));

// also reset current timeout
if (m_current_timeout && m_current_timeout->trigger == key)
m_current_timeout.reset();
}

void Stage::apply_output(ConstKeySequenceRange sequence,
Expand Down
18 changes: 13 additions & 5 deletions src/test/test0_ParseKeySequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,18 +328,26 @@ TEST_CASE("Input Expression", "[ParseKeySequence]") {
make_not_timeout_ms(1000, true),
KeyEvent(Key::B, KeyState::UpAsync),
KeyEvent(Key::A, KeyState::UpAsync),
KeyEvent(Key::A, KeyState::Up),
KeyEvent(Key::B, KeyState::Up), // <- unexpected that both need to be released
KeyEvent(Key::B, KeyState::Up),
KeyEvent(Key::A, KeyState::Up), // <- unexpected that both need to be released
}));

CHECK(parse_input("A{B{!1000ms}}") == (KeySequence{
KeyEvent(Key::A, KeyState::Down),
KeyEvent(Key::B, KeyState::Down),
make_not_timeout_ms(1000, true),
KeyEvent(Key::B, KeyState::UpAsync),
KeyEvent(Key::B, KeyState::Up),
KeyEvent(Key::A, KeyState::UpAsync),
}));

CHECK(parse_input("A{B !1000ms}") == (KeySequence{
KeyEvent(Key::A, KeyState::Down),
KeyEvent(Key::B, KeyState::Down),
KeyEvent(Key::B, KeyState::UpAsync),
make_not_timeout_ms(1000, true),
KeyEvent(Key::A, KeyState::UpAsync),
KeyEvent(Key::A, KeyState::Up),
KeyEvent(Key::B, KeyState::Up),
}));

CHECK(parse_input("A{1000ms !1000ms}") == (KeySequence{
Expand All @@ -359,8 +367,8 @@ TEST_CASE("Input Expression", "[ParseKeySequence]") {
make_not_timeout_ms(1000, true),
KeyEvent(Key::B, KeyState::UpAsync),
KeyEvent(Key::A, KeyState::UpAsync),
KeyEvent(Key::A, KeyState::Up),
KeyEvent(Key::B, KeyState::Up), // <- unexpected that both need to be released
KeyEvent(Key::B, KeyState::Up),
KeyEvent(Key::A, KeyState::Up), // <- unexpected that both need to be released
}));

// Timeouts are merged to minimize undefined behaviour
Expand Down
37 changes: 33 additions & 4 deletions src/test/test3_Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1829,10 +1829,10 @@ TEST_CASE("Timeout", "[Stage]") {

// E then interruption by E
CHECK(apply_input(stage, "+E") == "+1000ms");
CHECK(apply_input(stage, "-E") == "");
CHECK(apply_input(stage, "-E") == "+1000ms");
CHECK(apply_input(stage, reply_timeout_ms(999)) == "+E -E");
CHECK(apply_input(stage, "+E") == "+1000ms");
CHECK(apply_input(stage, "-E") == "");
CHECK(apply_input(stage, "-E") == "+1000ms");
CHECK(apply_input(stage, reply_timeout_ms(1000)) == "+Y -Y");
REQUIRE(stage.is_clear());

Expand Down Expand Up @@ -2321,8 +2321,37 @@ TEST_CASE("Not Timeout with modifier", "[Stage]") {
CHECK(apply_input(stage, "+ShiftLeft") == "");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(499)) == "");
CHECK(apply_input(stage, "-A") == "");
CHECK(apply_input(stage, "-ShiftLeft") == "+X -X");
CHECK(apply_input(stage, "-A") == "+X -X");
CHECK(apply_input(stage, "-ShiftLeft") == "");
REQUIRE(stage.is_clear());

// hold
CHECK(apply_input(stage, "+ShiftLeft") == "");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(500)) == "+ShiftLeft +A");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(500)) == "+A");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(499)) == "");
CHECK(apply_input(stage, "-A") == "-A +A -A");
CHECK(apply_input(stage, "-ShiftLeft") == "-ShiftLeft");
REQUIRE(stage.is_clear());

// tap after hold
CHECK(apply_input(stage, "+ShiftLeft") == "");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(500)) == "+ShiftLeft +A");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(499)) == "");
CHECK(apply_input(stage, "-A") == "-A +A -A");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(499)) == "");
CHECK(apply_input(stage, "-A") == "+X -X");
CHECK(apply_input(stage, "+A") == "?500ms");
CHECK(apply_input(stage, reply_timeout_ms(499)) == "");
CHECK(apply_input(stage, "-A") == "+X -X");
CHECK(apply_input(stage, "-ShiftLeft") == "-ShiftLeft");
REQUIRE(stage.is_clear());
}

//--------------------------------------------------------------------
Expand Down

0 comments on commit 8f58e25

Please sign in to comment.