Skip to content

Commit

Permalink
Proper output of Any key
Browse files Browse the repository at this point in the history
  • Loading branch information
houmain committed Jan 20, 2021
1 parent 725d563 commit ecb8a59
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 19 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ The command line argument ```-u``` causes the configuration to be automatically

The keys are named after their scancodes and not affected by the present keyboard layout.
The names have been chosen to match on what the [web browsers](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code) have agreed upon, so this [handy website](http://keycode.info/) can be used to get a key's name.

For convenience the letter and digits keys are also named ```A``` to ```Z``` and ```0``` to ```9```. The logical keys ```Shift```, ```Control```, ```Meta``` and ```Any``` are also defined (which match the keys the names suggest). There are also [virtual keys](#virtual-keys) for state switching.
For convenience the letter and digits keys are also named ```A``` to ```Z``` and ```0``` to ```9```. The logical keys ```Shift```, ```Control``` and ```Meta``` are also defined (each matches the left and right modifier keys). There are also [virtual keys](#virtual-keys) for state switching and an [Any](#any-key) key.

### Input expressions

Expand All @@ -56,7 +55,7 @@ The output expression format is analogous to the input expression format:

### Context awareness

In order to map an input expression to different output expressions, depending on the focused window, it first needs to be mapped to an abstract command. The command name can be chosen arbitrarily but must not be a key name:
In order to map an input expression to different output expressions, depending on the focused window, it first needs to be mapped to an abstract command. The command name can be chosen arbitrarily but must not be a key name. The configuration is case sensitive and all key names start with a capital letter, so it is advisable to begin command names with a lowercase letter:

```bash
Control{B} >> build
Expand Down Expand Up @@ -100,6 +99,17 @@ Virtual1{A} >> B
!Virtual1 E >> F
```

### Any key

```Any``` can be used in input and output expressions.
In input expressions it matches any key and in output expressions it outputs the current stroke.

```bash
# keep Control-A but map A to B
Control{Any} >> Any
A >> B
```

### Key aliases

For convenience aliases for keys can be defined:
Expand Down
10 changes: 0 additions & 10 deletions src/config/ParseConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ Config ParseConfig::operator()(std::istream& is) {
replace_logical_modifiers(*Key::Shift, *Key::ShiftLeft, *Key::ShiftRight);
replace_logical_modifiers(*Key::Control, *Key::ControlLeft, *Key::ControlRight);
replace_logical_modifiers(*Key::Meta, *Key::MetaLeft, *Key::MetaRight);
replace_any_key_in_output();

return std::move(m_config);
}
Expand Down Expand Up @@ -341,12 +340,3 @@ void ParseConfig::replace_logical_modifiers(KeyCode both, KeyCode left,
}
}
}

void ParseConfig::replace_any_key_in_output() {
const auto arbitrary_key = *Key::A;
for (auto& command : m_config.commands) {
replace_key(command.default_mapping, any_key, arbitrary_key);
for (auto& mapping : command.context_mappings)
replace_key(mapping.output, any_key, arbitrary_key);
}
}
1 change: 0 additions & 1 deletion src/config/ParseConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class ParseConfig {
std::string preprocess_ident(std::string ident) const;
std::string preprocess(It begin, It end) const;
void replace_logical_modifiers(KeyCode both, KeyCode left, KeyCode right);
void replace_any_key_in_output();

bool has_command(const std::string& name) const;
void add_command(std::string name, KeySequence input);
Expand Down
20 changes: 17 additions & 3 deletions src/runtime/Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <iterator>

namespace {
KeySequence::iterator find_key(KeySequence& sequence, KeyCode key) {
KeySequence::const_iterator find_key(const KeySequence& sequence, KeyCode key) {
return std::find_if(begin(sequence), end(sequence),
[&](const auto& ev) { return ev.key == key; });
}
Expand Down Expand Up @@ -174,12 +174,26 @@ void Stage::toggle_virtual_key(KeyCode key) {
m_sequence.emplace_back(key, KeyState::Down);
}

void Stage::output_current_sequence(const KeySequence& expression, KeyCode trigger) {
for (const auto& event : m_sequence) {
const auto it = find_key(expression, event.key);
if (it == expression.end() || it->state != KeyState::Not)
update_output(event, trigger);
}
}

void Stage::apply_output(const KeySequence& expression) {
for (const auto& event : expression)
if (is_virtual_key(event.key))
if (is_virtual_key(event.key)) {
toggle_virtual_key(event.key);
else
}
else if (event.key == any_key) {
if (event.state == KeyState::Down)
output_current_sequence(expression, m_sequence.back().key);
}
else {
update_output(event, m_sequence.back().key);
}
}

void Stage::forward_from_sequence() {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/Stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Stage {
void update_output(const KeyEvent& event, KeyCode trigger);
void finish_sequence();
void toggle_virtual_key(KeyCode key);
void output_current_sequence(const KeySequence& expression, KeyCode trigger);

const std::vector<Mapping> m_mappings;
const std::vector<MappingOverrideSet> m_override_sets;
Expand Down
44 changes: 42 additions & 2 deletions src/test/test2_MatchKeySequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,55 @@ TEST_CASE("Match status", "[MatchKeySequence]") {
TEST_CASE("Match Not", "[MatchKeySequence]") {
auto expr = KeySequence();

// TODO:
REQUIRE_NOTHROW(expr = parse_input("!A B C"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B +C")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B +C")) == MatchResult::match);

REQUIRE_NOTHROW(expr = parse_input("B !A C"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B +C")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B +C")) == MatchResult::match);

REQUIRE_NOTHROW(expr = parse_input("B C !A"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B +C")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B +C")) == MatchResult::match);

REQUIRE_NOTHROW(expr = parse_input("B{!A C}"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B +C")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B +C")) == MatchResult::match);
}

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

TEST_CASE("Match ANY", "[MatchKeySequence]") {
auto expr = KeySequence();

// TODO:
REQUIRE_NOTHROW(expr = parse_input("Any"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::match);

REQUIRE_NOTHROW(expr = parse_input("Any B"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B -B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B -B +B")) == MatchResult::match);
CHECK(match(expr, parse_sequence("+B -B +C")) == MatchResult::no_match);

REQUIRE_NOTHROW(expr = parse_input("Any{B}"));
CHECK(match(expr, parse_sequence("+A")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B")) == MatchResult::might_match);
CHECK(match(expr, parse_sequence("+B -B")) == MatchResult::no_match);
CHECK(match(expr, parse_sequence("+A +B")) == MatchResult::match);
}

//--------------------------------------------------------------------
105 changes: 105 additions & 0 deletions src/test/test3_Stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ TEST_CASE("Might match, then no match or match", "[Stage]") {
REQUIRE(apply_input(stage, "+B") == "+2");
REQUIRE(apply_input(stage, "-B") == "-2");
}

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

TEST_CASE("Keyrepeat might match", "[Stage]") {
Expand All @@ -593,6 +594,110 @@ TEST_CASE("Keyrepeat might match", "[Stage]") {
REQUIRE(apply_input(stage, "+C") == "+ControlLeft +C");
REQUIRE(apply_input(stage, "-C") == "-ControlLeft -C");
REQUIRE(apply_input(stage, "-MetaLeft") == "");

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

REQUIRE(apply_input(stage, "+MetaLeft") == "");
REQUIRE(apply_input(stage, "+MetaLeft") == "");
REQUIRE(apply_input(stage, "-MetaLeft") == "+MetaLeft -MetaLeft");
}

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

TEST_CASE("Any key", "[Stage]") {
auto config = R"(
Meta >> Meta
Meta{Any} >> Any
A >> B
E >> F
M A >> S
M B >> Any
M C >> !M Any
K >> Any S
X Y >> Any T
)";
Stage stage = create_stage(config);

REQUIRE(apply_input(stage, "+A") == "+B");
REQUIRE(apply_input(stage, "-A") == "-B");
REQUIRE(apply_input(stage, "+E") == "+F");
REQUIRE(apply_input(stage, "-E") == "-F");
REQUIRE(apply_input(stage, "+H") == "+H");
REQUIRE(apply_input(stage, "-H") == "-H");
REQUIRE(format_sequence(stage.sequence()) == "");

REQUIRE(apply_input(stage, "+MetaLeft") == "+MetaLeft");
REQUIRE(apply_input(stage, "+A") == "+A");
REQUIRE(apply_input(stage, "+E") == "+E");
REQUIRE(apply_input(stage, "+H") == "+H");
REQUIRE(apply_input(stage, "-A") == "-A");
REQUIRE(apply_input(stage, "-E") == "-E");
REQUIRE(apply_input(stage, "-H") == "-H");
REQUIRE(apply_input(stage, "-MetaLeft") == "-MetaLeft");
REQUIRE(format_sequence(stage.sequence()) == "");

REQUIRE(apply_input(stage, "+K") == "+K +S");
REQUIRE(apply_input(stage, "-K") == "-K -S");
REQUIRE(format_sequence(stage.sequence()) == "");

REQUIRE(apply_input(stage, "+X") == "");
REQUIRE(apply_input(stage, "+Y") == "+X +Y +T");
REQUIRE(apply_input(stage, "-X") == "");
REQUIRE(apply_input(stage, "-Y") == "-X -Y -T");
}

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

TEST_CASE("Any key might match", "[Stage]") {
auto config = R"(
M A >> S
M B >> Any
M C >> !M Any
N >> N
N A >> S
N B >> Any
N C >> !N Any
)";
Stage stage = create_stage(config);

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

REQUIRE(apply_input(stage, "+M") == "");
REQUIRE(apply_input(stage, "+B") == "+M +B");
REQUIRE(apply_input(stage, "-B") == "-M -B");
REQUIRE(apply_input(stage, "-M") == "");

REQUIRE(apply_input(stage, "+M") == "");
REQUIRE(apply_input(stage, "+C") == "+C");
REQUIRE(apply_input(stage, "-C") == "-C");
REQUIRE(apply_input(stage, "-M") == "");
REQUIRE(format_sequence(stage.sequence()) == "");

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

REQUIRE(apply_input(stage, "+N") == "+N");
REQUIRE(apply_input(stage, "+B") == "+B");
REQUIRE(apply_input(stage, "-B") == "-B");
REQUIRE(apply_input(stage, "-N") == "-N");

REQUIRE(apply_input(stage, "+N") == "+N");
REQUIRE(apply_input(stage, "+C") == "-N +C");
REQUIRE(apply_input(stage, "-C") == "-C");
REQUIRE(apply_input(stage, "-N") == "");
REQUIRE(format_sequence(stage.sequence()) == "");
}

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

0 comments on commit ecb8a59

Please sign in to comment.