From f78adeda498fb9eb58b9ce334156f8f3606806c3 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 30 Apr 2021 14:48:37 +1000 Subject: [PATCH] src: Fix mouse modifier support in the ncurses UI. For historical reasons, mouse events represent keyboard modifiers as a bitfield, but keyboard events represent modifiers as a bitfield-plus-one. For example, a mouse event with an Alt modifier will use the value 4, but a keyboard event will use the value 5. Previously, I refactored the parse_mask() helper to do the subtraction itself, instead of requiring the caller to do it. This made keyboard-event decoding much cleaner, but I didn't realise it broke mouse-event decoding. Now the subtraction is done only for keyboard events. Fixes #4176. --- src/ncurses_ui.cc | 67 +++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 68843135..fce51cb7 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -668,7 +668,6 @@ Optional NCursesUI::get_next_key() }; auto parse_mask = [](int mask) { - mask = std::max(mask - 1, 0); Key::Modifiers mod = Key::Modifiers::None; if (mask & 1) mod |= Key::Modifiers::Shift; @@ -721,7 +720,10 @@ Optional NCursesUI::get_next_key() (Codepoint)((down ? 1 : -1) * m_wheel_scroll_amount)}; }; - auto masked_key = [&](Codepoint key) { return Key{parse_mask(params[1]), key}; }; + auto masked_key = [&](Codepoint key) { + int mask = std::max(params[1] - 1, 0); + return Key{parse_mask(mask), key}; + }; switch (c) { @@ -810,39 +812,40 @@ Optional NCursesUI::get_next_key() raw_mask = raw_mask * 10 + (code - '0'); code = get_char().value_or((unsigned char)0xff); } while (code >= '0' and code <= '9'); + Key::Modifiers mod = parse_mask(std::max(raw_mask - 1, 0)); switch (code) { - case ' ': return Key{parse_mask(raw_mask), ' '}; - case 'A': return Key{parse_mask(raw_mask), Key::Up}; - case 'B': return Key{parse_mask(raw_mask), Key::Down}; - case 'C': return Key{parse_mask(raw_mask), Key::Right}; - case 'D': return Key{parse_mask(raw_mask), Key::Left}; - case 'F': return Key{parse_mask(raw_mask), Key::End}; - case 'H': return Key{parse_mask(raw_mask), Key::Home}; - case 'I': return Key{parse_mask(raw_mask), Key::Tab}; - case 'M': return Key{parse_mask(raw_mask), Key::Return}; - case 'P': return Key{parse_mask(raw_mask), Key::F1}; - case 'Q': return Key{parse_mask(raw_mask), Key::F2}; - case 'R': return Key{parse_mask(raw_mask), Key::F3}; - case 'S': return Key{parse_mask(raw_mask), Key::F4}; - case 'X': return Key{parse_mask(raw_mask), '='}; - case 'j': return Key{parse_mask(raw_mask), '*'}; - case 'k': return Key{parse_mask(raw_mask), '+'}; - case 'l': return Key{parse_mask(raw_mask), ','}; - case 'm': return Key{parse_mask(raw_mask), '-'}; - case 'n': return Key{parse_mask(raw_mask), '.'}; - case 'o': return Key{parse_mask(raw_mask), '/'}; - case 'p': return Key{parse_mask(raw_mask), '0'}; - case 'q': return Key{parse_mask(raw_mask), '1'}; - case 'r': return Key{parse_mask(raw_mask), '2'}; - case 's': return Key{parse_mask(raw_mask), '3'}; - case 't': return Key{parse_mask(raw_mask), '4'}; - case 'u': return Key{parse_mask(raw_mask), '5'}; - case 'v': return Key{parse_mask(raw_mask), '6'}; - case 'w': return Key{parse_mask(raw_mask), '7'}; - case 'x': return Key{parse_mask(raw_mask), '8'}; - case 'y': return Key{parse_mask(raw_mask), '9'}; + case ' ': return Key{mod, ' '}; + case 'A': return Key{mod, Key::Up}; + case 'B': return Key{mod, Key::Down}; + case 'C': return Key{mod, Key::Right}; + case 'D': return Key{mod, Key::Left}; + case 'F': return Key{mod, Key::End}; + case 'H': return Key{mod, Key::Home}; + case 'I': return Key{mod, Key::Tab}; + case 'M': return Key{mod, Key::Return}; + case 'P': return Key{mod, Key::F1}; + case 'Q': return Key{mod, Key::F2}; + case 'R': return Key{mod, Key::F3}; + case 'S': return Key{mod, Key::F4}; + case 'X': return Key{mod, '='}; + case 'j': return Key{mod, '*'}; + case 'k': return Key{mod, '+'}; + case 'l': return Key{mod, ','}; + case 'm': return Key{mod, '-'}; + case 'n': return Key{mod, '.'}; + case 'o': return Key{mod, '/'}; + case 'p': return Key{mod, '0'}; + case 'q': return Key{mod, '1'}; + case 'r': return Key{mod, '2'}; + case 's': return Key{mod, '3'}; + case 't': return Key{mod, '4'}; + case 'u': return Key{mod, '5'}; + case 'v': return Key{mod, '6'}; + case 'w': return Key{mod, '7'}; + case 'x': return Key{mod, '8'}; + case 'y': return Key{mod, '9'}; default: return {}; } };