aboutsummaryrefslogtreecommitdiff
path: root/ttwhy/terminal/policies.cppm
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2026-10-26 19:15:33 +0100
committerFelix Morgner <felix.morgner@gmail.com>2026-10-26 19:15:33 +0100
commitb051983db21290871c7a33cf8189f415c07f8a24 (patch)
tree4258f9fdc05f5eec0341147047d8eb40ea055454 /ttwhy/terminal/policies.cppm
parent79a35574ce6d472f7a7cc4a200a1ed7befe34066 (diff)
downloadttwhy-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.cppm159
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});
+ }
}
};