From: Lennart Poettering Date: Sun, 2 Mar 2025 20:40:50 +0000 (+0100) Subject: ptyfwd: add support for additional out-of-band hotkeys in ptyfwd X-Git-Tag: v258-rc1~1186^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b1f9d0e46bbb0f84b0c150af907e257e341baf73;p=thirdparty%2Fsystemd.git ptyfwd: add support for additional out-of-band hotkeys in ptyfwd Let's add the ability that ptyfwd tools can register additional hotkeys that they then can handle. So far the only hotkey we support is ^]^]^] to exit the ptyfwd session abruptly. Staying close to this let's add ^]^] for additional commands. --- diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 8c3ea6b5ae9..d434f8e850f 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -103,6 +103,8 @@ struct PTYForward { PTYForwardHangupHandler hangup_handler; void *hangup_userdata; + PTYForwardHotkeyHandler hotkey_handler; + void *hotkey_userdata; char *background_color; AnsiColorState ansi_color_state; @@ -198,17 +200,26 @@ static int pty_forward_done(PTYForward *f, int rcode) { return sd_event_exit(e, rcode < 0 ? EXIT_FAILURE : rcode); } -static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) { - const char *p; - +typedef enum RequestOperation { + REQUEST_NOP, + REQUEST_EXIT, + REQUEST_HOTKEY_BASE, + REQUEST_HOTKEY_A = REQUEST_HOTKEY_BASE + 'a', + REQUEST_HOTKEY_Z = REQUEST_HOTKEY_BASE + 'z', + _REQUEST_OPERATION_MAX, + _REQUEST_OPERATION_INVALID = -EINVAL, +} RequestOperation; + +static RequestOperation look_for_escape(PTYForward *f, const char *buffer, size_t n) { assert(f); assert(buffer); assert(n > 0); - for (p = buffer; p < buffer + n; p++) { + for (const char *p = buffer; p < buffer + n; p++) { + + switch (*p) { - /* Check for ^] */ - if (*p == 0x1D) { + case 0x1D: { /* Check for ^] */ usec_t nw = now(CLOCK_MONOTONIC); if (f->escape_counter == 0 || nw > f->escape_timestamp + ESCAPE_USEC) { @@ -218,15 +229,29 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) { (f->escape_counter)++; if (f->escape_counter >= 3) - return true; + return REQUEST_EXIT; } - } else { + + break; + } + + case 'a'...'z': + if (f->escape_counter == 2 && + now(CLOCK_MONOTONIC) <= f->escape_timestamp + ESCAPE_USEC) { + f->escape_timestamp = 0; + f->escape_counter = 0; + return REQUEST_HOTKEY_BASE + *p; + } + + _fallthrough_; + + default: f->escape_timestamp = 0; f->escape_counter = 0; } } - return false; + return REQUEST_NOP; } static bool ignore_vhangup(PTYForward *f) { @@ -654,10 +679,17 @@ static int do_shovel(PTYForward *f) { } else { /* Check if ^] has been pressed three times within one second. If we get this we quite * immediately. */ - if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k)) - return -ECANCELED; - + RequestOperation q = look_for_escape(f, f->in_buffer + f->in_buffer_full, k); f->in_buffer_full += (size_t) k; + if (q < 0) + return q; + if (q == REQUEST_EXIT) + return -ECANCELED; + if (q >= REQUEST_HOTKEY_A && q <= REQUEST_HOTKEY_Z && f->hotkey_handler) { + r = f->hotkey_handler(f, q - REQUEST_HOTKEY_BASE, f->hotkey_userdata); + if (r < 0) + return r; + } } did_something = true; @@ -1091,6 +1123,13 @@ void pty_forward_set_hangup_handler(PTYForward *f, PTYForwardHangupHandler cb, v f->hangup_userdata = userdata; } +void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler cb, void *userdata) { + assert(f); + + f->hotkey_handler = cb; + f->hotkey_userdata = userdata; +} + bool pty_forward_drain(PTYForward *f) { assert(f); diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index 8f096e42cba..b276cb15c59 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -24,6 +24,7 @@ typedef enum PTYForwardFlags { } PTYForwardFlags; typedef int (*PTYForwardHangupHandler)(PTYForward *f, int rcode, void *userdata); +typedef int (*PTYForwardHotkeyHandler)(PTYForward *f, char key, void *userdata); #define N_PTY_FORWARD_SIGNALS 7 extern const int pty_forward_signals[N_PTY_FORWARD_SIGNALS]; @@ -35,6 +36,7 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup); bool pty_forward_get_ignore_vhangup(PTYForward *f); void pty_forward_set_hangup_handler(PTYForward *f, PTYForwardHangupHandler handler, void *userdata); +void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler handler, void *userdata); bool pty_forward_drain(PTYForward *f);