diff --git a/cmd-split-window.c b/cmd-split-window.c index e919b6f03..4980d6a9b 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-split-window.c,v 1.148 2026/08/07 08:10:53 nicm Exp $ */ +/* $OpenBSD: cmd-split-window.c,v 1.149 2026/08/19 10:56:10 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -41,8 +41,8 @@ const struct cmd_entry cmd_new_pane_entry = { .name = "new-pane", .alias = "newp", - .args = { "bB:Cc:de:EfF:hIkl:LMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL }, - .usage = "[-bCdefhIklMOPvWZ] [-B border-lines] " + .args = { "bB:Cc:de:EfF:hIkl:KLMm:Op:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL }, + .usage = "[-bCdefhIkKLMOPvWZ] [-B border-lines] " "[-c start-directory] [-e environment] " "[-F format] [-l size] [-m message] [-p percentage] " "[-s style] [-S active-border-style] " @@ -203,6 +203,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) */ goto fail; } + if (args_has(args, 'K') && args_has(args, 'O')) + new_wp->flags |= PANE_CAPTUREALLKEYS; if (args_has(args, 'C') && args_has(args, 'O')) new_wp->flags |= PANE_CLOSEONCLICK; diff --git a/server-client.c b/server-client.c index 4fe4917ad..a631a90a9 100644 --- a/server-client.c +++ b/server-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server-client.c,v 1.503 2026/08/17 07:56:56 nicm Exp $ */ +/* $OpenBSD: server-client.c,v 1.504 2026/08/19 10:56:10 nicm Exp $ */ /* * Copyright (c) 2009 Nicholas Marriott @@ -50,6 +50,7 @@ static void server_client_set_path(struct client *); static void server_client_set_progress_bar(struct client *); static void server_client_reset_state(struct client *); static void server_client_update_latest(struct client *); +static int server_client_handle_dead_key(struct window_pane *, key_code); static void server_client_dispatch(struct imsg *, void *); static int server_client_dispatch_command(struct client *, struct imsg *); static int server_client_dispatch_identify(struct client *, struct imsg *); @@ -1393,6 +1394,21 @@ server_client_repeat_time(struct client *c, struct key_binding *bd) return (repeat); } +/* Handle a key press on a dead pane waiting for a key. */ +static int +server_client_handle_dead_key(struct window_pane *wp, key_code key) +{ + if (wp == NULL || + (~wp->flags & PANE_EXITED) || + KEYC_IS_MOUSE(key) || + KEYC_IS_PASTE(key) || + options_get_number(wp->options, "remain-on-exit") != 3) + return (0); + options_set_number(wp->options, "remain-on-exit", 0); + server_destroy_pane(wp, 0); + return (1); +} + /* * Handle data key input from client. This owns and can modify the key event it * is given and is responsible for freeing it. @@ -1478,6 +1494,14 @@ server_client_key_callback(struct cmdq_item *item, void *data) server_client_is_assume_paste(c)) goto paste_key; + /* Forward keys directly if this pane is capturing all keys. */ + if (wp != NULL && + (wp->flags & PANE_CAPTUREALLKEYS) && + (~wp->flags & PANE_EXITED) && + !KEYC_IS_MOUSE(key) && + TAILQ_EMPTY(&wp->modes)) + goto forward_key; + /* * Work out the current key table. If the pane is in a mode, use * the mode table instead of the default key table. @@ -1642,15 +1666,8 @@ try_again: } forward_key: - if (wp != NULL && - (wp->flags & PANE_EXITED) && - !KEYC_IS_MOUSE(key) && - !KEYC_IS_PASTE(key) && - options_get_number(wp->options, "remain-on-exit") == 3) { - options_set_number(wp->options, "remain-on-exit", 0); - server_destroy_pane(wp, 0); + if (server_client_handle_dead_key(wp, key)) goto out; - } if (c->flags & CLIENT_READONLY) goto out; if (wp != NULL) @@ -1738,9 +1755,9 @@ server_client_handle_key0(struct client *c, struct key_event *event, } /* - * Key presses in overlay mode and the command prompt are a special - * case. The queue might be blocked so they need to be processed - * immediately rather than queued. + * Key presses in overlay mode, for panes capturing all keys and in the + * command prompt are a special case. The queue might be blocked so they + * need to be processed immediately rather than queued. */ if (~c->flags & CLIENT_READONLY) { if (c->message_string != NULL) { @@ -1760,6 +1777,21 @@ server_client_handle_key0(struct client *c, struct key_event *event, } server_client_clear_overlay(c); + + wp = s->curw->window->active; + if (wp != NULL && + (wp->flags & PANE_CAPTUREALLKEYS) && + TAILQ_EMPTY(&wp->modes) && + !KEYC_IS_MOUSE(event->key)) { + if (server_client_handle_dead_key(wp, event->key)) + return (0); + if (~wp->flags & PANE_EXITED) { + window_pane_key(wp, c, s, s->curw, event->key, + &event->m); + return (0); + } + } + if (server_client_handle_menu_key(c, event)) return (0); if (c->prompt != NULL) { diff --git a/tmux.1 b/tmux.1 index de987b22d..1b692f05a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.1156 2026/08/17 14:47:41 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.1157 2026/08/19 10:56:10 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -14,7 +14,7 @@ .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: August 17 2026 $ +.Dd $Mdocdate: August 19 2026 $ .Dt TMUX 1 .Os .Sh NAME @@ -3642,7 +3642,7 @@ but a different format may be specified with .Fl F . .Tg newp .It Xo Ic new\-pane -.Op Fl bCdefhIkLMOPvWZ +.Op Fl bCdefhIkKLMOPvWZ .Op Fl B Ar border\-lines .Op Fl c Ar start\-directory .Op Fl e Ar environment @@ -3699,6 +3699,9 @@ A modal pane is always the active pane and prevents interaction with any other panes while it is active. A window can only have one modal pane and it must be a floating pane. With +.Fl K , +all keys, including the prefix key, are passed directly to the modal pane. +With .Fl C , the modal pane is closed when the mouse is clicked outside it. .Pp diff --git a/tmux.h b/tmux.h index 68d2044b0..b295e2313 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1427 2026/08/18 09:01:20 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1428 2026/08/19 10:56:10 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1301,6 +1301,7 @@ struct window_pane { #define PANE_CMDRUNNING 0x20000 #define PANE_ACTIVITY 0x40000 #define PANE_CLOSEONCLICK 0x80000 +#define PANE_CAPTUREALLKEYS 0x100000 bitstr_t *sync_dirty; u_int sync_dirty_size;