Skip to content

Commit 821ef02

Browse files
committed
Fixed device context fallthrough (#277)
1 parent 3ad8bb0 commit 821ef02

File tree

4 files changed

+32
-10
lines changed

4 files changed

+32
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
1717

1818
- Not blocking when opening configuration from tray on Linux (#220).
1919
- Fixed focus update when xwayland app is minimized to tray (#220).
20+
- Fixed device context fallthrough (#277).
2021
- Optimized SVG icon.
2122

2223
## [Version 4.12.1] - 2025-05-20

src/runtime/Stage.cpp

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ KeySequence Stage::set_active_client_contexts(const std::vector<int> &indices) {
199199
assert(i >= 0 && i < static_cast<int>(m_contexts.size()));
200200

201201
m_active_client_contexts = indices;
202-
update_active_contexts();
202+
update_active_contexts(any_device_index);
203203

204204
// cancel output on release when the focus changed
205205
cancel_inactive_output_on_release();
@@ -218,15 +218,15 @@ bool Stage::match_context_modifier_filter(const KeySequence& modifiers) {
218218
return true;
219219
}
220220

221-
void Stage::update_active_contexts() {
221+
void Stage::update_active_contexts(int device_index) {
222222
std::swap(m_prev_active_contexts, m_active_contexts);
223223

224224
// evaluate modifier and device filter of contexts which were set active by client
225225
m_active_contexts.clear();
226226
for (auto index : m_active_client_contexts) {
227227
const auto& context = m_contexts[index];
228228
if ((match_context_modifier_filter(context.modifier_filter) ^ context.invert_modifier_filter) &&
229-
((!context.device_filter && !context.device_id_filter) || context.matching_device_bits)) {
229+
device_matches_filter(context, device_index)) {
230230
index = fallthrough_context(index);
231231
if (m_active_contexts.empty() || m_active_contexts.back() != index)
232232
m_active_contexts.push_back(index);
@@ -385,9 +385,6 @@ auto Stage::match_input(bool first_iteration, bool matched_are_optional,
385385

386386
for (auto context_index : m_active_contexts) {
387387
const auto& context = m_contexts[context_index];
388-
if (!device_matches_filter(context, device_index))
389-
continue;
390-
391388
for (const auto& context_input : context.inputs) {
392389
const auto& input = context_input.input;
393390
const auto no_might_match_mapping =
@@ -508,7 +505,7 @@ void Stage::apply_input(const KeyEvent event, int device_index) {
508505
}
509506

510507
// update contexts with modifier filter
511-
update_active_contexts();
508+
update_active_contexts(device_index);
512509

513510
if (event.state == KeyState::Up) {
514511

@@ -668,7 +665,7 @@ void Stage::apply_input(const KeyEvent event, int device_index) {
668665
release_triggered(event.key);
669666

670667
// update contexts with modifier filter
671-
update_active_contexts();
668+
update_active_contexts(device_index);
672669

673670
// remove matched timeout events
674671
while (!m_sequence.empty() &&

src/runtime/Stage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class Stage {
7373
void update_output(const KeyEvent& event, const Trigger& trigger, int context_index = -1);
7474
void finish_sequence(ConstKeySequenceRange sequence);
7575
bool match_context_modifier_filter(const KeySequence& modifiers);
76-
void update_active_contexts();
76+
void update_active_contexts(int device_index);
7777
bool continue_output_on_release(const KeyEvent& event, int context_index = -1);
7878
void cancel_inactive_output_on_release();
7979
int fallthrough_context(int context_index) const;

src/test/test4_Server.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ namespace {
139139
indices.push_back(i);
140140
state.set_active_contexts(indices);
141141

142-
state.set_device_descs({ DeviceDesc{ "Device0" } });
142+
state.set_device_descs({
143+
DeviceDesc{ "Device0" },
144+
DeviceDesc{ "Device1" },
145+
DeviceDesc{ "Device2" },
146+
});
143147
return state;
144148
}
145149
} // namespace
@@ -920,3 +924,23 @@ TEST_CASE("Keyrepeat triggers last matching mapping (#275)", "[Server]") {
920924
CHECK(state.apply_input("-C") == "");
921925
REQUIRE(state.stage_is_clear());
922926
}
927+
928+
//--------------------------------------------------------------------
929+
930+
TEST_CASE("Context with device filter fallthrough", "[Server]") {
931+
auto state = create_state(R"(
932+
[device = "Device0"]
933+
[device = "Device1"]
934+
A >> X
935+
936+
[default]
937+
A >> Y
938+
)");
939+
940+
CHECK(state.apply_input("+A", 0) == "+X");
941+
CHECK(state.apply_input("-A", 0) == "-X");
942+
CHECK(state.apply_input("+A", 1) == "+X");
943+
CHECK(state.apply_input("-A", 1) == "-X");
944+
CHECK(state.apply_input("+A", 2) == "+Y");
945+
CHECK(state.apply_input("-A", 2) == "-Y");
946+
}

0 commit comments

Comments
 (0)