diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-10-26 19:15:33 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-10-26 19:15:33 +0100 |
| commit | b051983db21290871c7a33cf8189f415c07f8a24 (patch) | |
| tree | 4258f9fdc05f5eec0341147047d8eb40ea055454 /ttwhy/terminal/policies.cppm | |
| parent | 79a35574ce6d472f7a7cc4a200a1ed7befe34066 (diff) | |
| download | ttwhy-b051983db21290871c7a33cf8189f415c07f8a24.tar.xz ttwhy-b051983db21290871c7a33cf8189f415c07f8a24.zip | |
terminal: improve function and control key handling
Diffstat (limited to 'ttwhy/terminal/policies.cppm')
| -rw-r--r-- | ttwhy/terminal/policies.cppm | 159 |
1 files changed, 137 insertions, 22 deletions
diff --git a/ttwhy/terminal/policies.cppm b/ttwhy/terminal/policies.cppm index 83694b8..49712aa 100644 --- a/ttwhy/terminal/policies.cppm +++ b/ttwhy/terminal/policies.cppm @@ -12,29 +12,99 @@ namespace ttwhy::terminal namespace detail { - constexpr auto map_vt220_keypad(char terminator) -> std::optional<navigation_key> + constexpr auto parse_primary_parameter(std::string_view buffer) -> std::optional<unsigned int> { - switch (terminator) + auto delimiter = buffer.find(';'); + auto primary_slice = buffer.substr(0, delimiter); + if (primary_slice.empty()) + { + return std::nullopt; + } + + auto value = 0u; + for (auto character : primary_slice) + { + if (character < '0' || character > '9') + { + return std::nullopt; + } + value = value * 10 + static_cast<unsigned int>(character - '0'); + } + return value; + } + + constexpr auto map_vt220_navigation(unsigned int code) -> std::optional<navigation_key> + { + switch (code) { - case '1': - case '7': + case 1: + case 7: return navigation_key::home; - case '2': + case 2: return navigation_key::insert_key; - case '3': + case 3: return navigation_key::delete_key; - case '4': - case '8': + case 4: + case 8: return navigation_key::end; - case '5': + case 5: return navigation_key::page_up; - case '6': + case 6: return navigation_key::page_down; default: return std::nullopt; } } + constexpr auto map_vt220_function(unsigned int code) -> std::optional<function_key> + { + switch (code) + { + case 11: + return function_key::f1; + case 12: + return function_key::f2; + case 13: + return function_key::f3; + case 14: + return function_key::f4; + case 15: + return function_key::f5; + case 17: + return function_key::f6; + case 18: + return function_key::f7; + case 19: + return function_key::f8; + case 20: + return function_key::f9; + case 21: + return function_key::f10; + case 23: + return function_key::f11; + case 24: + return function_key::f12; + case 25: + return function_key::f13; + case 26: + return function_key::f14; + case 28: + return function_key::f15; + case 29: + return function_key::f16; + case 31: + return function_key::f17; + case 32: + return function_key::f18; + case 33: + return function_key::f19; + case 34: + return function_key::f20; + default: + return std::nullopt; + } + } + constexpr auto map_vt100_cursor(char terminator) -> std::optional<navigation_key> { switch (terminator) @@ -56,15 +126,32 @@ namespace ttwhy::terminal } } + constexpr auto map_ss3_function(char terminator) -> std::optional<function_key> + { + switch (terminator) + { + case 'P': + return function_key::f1; + case 'Q': + return function_key::f2; + case 'R': + return function_key::f3; + case 'S': + return function_key::f4; + default: + return std::nullopt; + } + } + } // namespace detail //! Policy for decoding standard ANSI/VT escape sequences. export struct ansi_policy { - //! Resolve a VT220 keypad sequence and emit the corresponding navigation event. + //! Resolve a VT220 keypad sequence and emit the corresponding navigation or function event. //! //! @param buffer The CSI parameter buffer. - //! @param sink The event sink to receive the resolved navigation event. + //! @param sink The event sink to receive the resolved event. constexpr auto static resolve_vt220_keypad(std::string & buffer, event_sink auto & sink) -> void { if (buffer.empty()) @@ -72,9 +159,16 @@ namespace ttwhy::terminal return; } - if (auto key = detail::map_vt220_keypad(buffer.front())) + if (auto code = detail::parse_primary_parameter(buffer)) { - sink(navigation_event{*key}); + if (auto key = detail::map_vt220_navigation(*code)) + { + sink(navigation_event{*key}); + } + else if (auto key = detail::map_vt220_function(*code)) + { + sink(function_key_event{*key}); + } } buffer.clear(); } @@ -91,16 +185,20 @@ namespace ttwhy::terminal } } - //! Resolve an SS3 single-shift sequence and emit the corresponding navigation event. + //! Resolve an SS3 single-shift sequence and emit the corresponding navigation or function event. //! //! @param terminator The SS3 terminator character indicating direction or key. - //! @param sink The event sink to receive the resolved navigation event. + //! @param sink The event sink to receive the resolved event. constexpr auto static resolve_ss3(char terminator, event_sink auto & sink) -> void { if (auto key = detail::map_vt100_cursor(terminator)) { sink(navigation_event{*key}); } + else if (auto key = detail::map_ss3_function(terminator)) + { + sink(function_key_event{*key}); + } } }; @@ -120,6 +218,12 @@ namespace ttwhy::terminal } auto modifier_string = buffer.substr(delimiter + 1); + auto next_delimiter = modifier_string.find(';'); + if (next_delimiter != std::string_view::npos) + { + modifier_string = modifier_string.substr(0, next_delimiter); + } + auto modifier_value = 0u; for (auto character : modifier_string) @@ -138,10 +242,10 @@ namespace ttwhy::terminal return static_cast<modifier_set>(modifier_value - 1); } - //! Resolve a VT220 keypad sequence with modifiers and emit the navigation event. + //! Resolve a VT220 keypad sequence with modifiers and emit the navigation or function event. //! //! @param buffer The CSI parameter buffer containing key and modifier values. - //! @param sink The event sink to receive the resolved navigation event. + //! @param sink The event sink to receive the resolved event. constexpr auto static resolve_vt220_keypad(std::string & buffer, event_sink auto & sink) -> void { if (buffer.empty()) @@ -151,9 +255,16 @@ namespace ttwhy::terminal auto modifiers = parse_modifiers(buffer); - if (auto key = detail::map_vt220_keypad(buffer.front())) + if (auto code = detail::parse_primary_parameter(buffer)) { - sink(navigation_event{*key, modifiers}); + if (auto key = detail::map_vt220_navigation(*code)) + { + sink(navigation_event{*key, modifiers}); + } + else if (auto key = detail::map_vt220_function(*code)) + { + sink(function_key_event{*key, modifiers}); + } } buffer.clear(); } @@ -173,16 +284,20 @@ namespace ttwhy::terminal } } - //! Resolve an SS3 single-shift sequence and emit the corresponding navigation event. + //! Resolve an SS3 single-shift sequence and emit the corresponding navigation or function event. //! //! @param terminator The SS3 terminator character indicating direction or key. - //! @param sink The event sink to receive the resolved navigation event. + //! @param sink The event sink to receive the resolved event. constexpr auto static resolve_ss3(char terminator, event_sink auto & sink) -> void { if (auto key = detail::map_vt100_cursor(terminator)) { sink(navigation_event{*key}); } + else if (auto key = detail::map_ss3_function(terminator)) + { + sink(function_key_event{*key}); + } } }; |
