From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id GRjDOaO39GnsKgkAWB0awg (envelope-from ) for ; Fri, 01 May 2026 10:24:35 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bUjlz4R9; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id E721B1E0BA; Fri, 01 May 2026 10:24:35 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_MSPIKE_H2,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id AF5191E067 for ; Fri, 01 May 2026 10:24:34 -0400 (EDT) Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 76BC14374200 for ; Fri, 1 May 2026 14:24:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 76BC14374200 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=bUjlz4R9 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 539EF43B551C for ; Fri, 1 May 2026 14:23:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 539EF43B551C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 539EF43B551C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777645386; cv=none; b=eel5szeNIGM8scLk+bZ304PM4By9bTtbzv/1Avhj4iQE2Xcf5RO3JCxujayiMR/fq29FmY0e7/1Rn7CmJntG2zrrb/RCBIq0RBlB2a5DVvNcqke9Gs5Z3ycLTb2KMQlpVfFOUHX56qbsSZ/Xc3IAH4OU78D5z9zxFNGIpe3M9LA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777645386; c=relaxed/simple; bh=BifibxiNKx//YTzLiPQBMFMzNy9W6z2pOfvJJ6bl9/0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=YhKMLI0MnFvGGlqLXIA71ra1Ouhx+Wxh0rxECCpwXmmlAHyP89Gk31K0AxSWeGlsCOKANctSRNqDWvOVkpI/v3sJAQRPu0VzTtiP4lO16YLRnKVwB9z8PtAS8NbQNBs9Q6cNW9dpNd2NZ4wKDB8PQj4/EmJbyCAv4VfcRB8gKTo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 539EF43B551C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1777645386; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=PMyr827+lg4pcWoNEDkFtzp5SZMS18YAyce/xv8F/Bk=; b=bUjlz4R98KTurPpqFUGPQb2V3urrOW9fZDSQJ9kzPWle/KH9nxyFUQ1nrGdxaObQOzJvNY jklwu6O5oAjF47Lb/8T0NijJuDIE3cxkC2mz9hbgcv47AnPxu/2FgZTC4vh8XoTeFvM0wa dlgVxYIySaLhxUEHR3Q2QXBm4ed5azQ= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-626-YrXRIGPYODysHsZ9HAKKSA-1; Fri, 01 May 2026 10:23:04 -0400 X-MC-Unique: YrXRIGPYODysHsZ9HAKKSA-1 X-Mimecast-MFC-AGG-ID: YrXRIGPYODysHsZ9HAKKSA_1777645383 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-488d56f87e8so15262985e9.0 for ; Fri, 01 May 2026 07:23:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777645383; x=1778250183; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=PMyr827+lg4pcWoNEDkFtzp5SZMS18YAyce/xv8F/Bk=; b=azGMLqKj4YxchVl6TmGRORAIHK4URqf5z1cFvwGqgw7VvMPCACwhbUodfS12PgkftR XP89PPxCoXFVcn1sA0yKn6Ml7x7l936z2Bosk3RRQfEPnjA8xY9LV8hmKgi4C+xkAQyB 1yt8f1BCVqJY4ae3GkmphVH6AbDDCTvCskVXX3puCWL4KNtM29evzY+QN4xgwnbr2mCs 5LkCJWOVxEt6JK0wvIBurR/PRoJMT7sYl9y/xcD2oCaX9L+uRCEfkN3YXyQiuOZ14NEv WwR6h2STFRiyNDCp65UOZDCNivrCui38bDRU4b0r3fuVYnMnAdycQ39uzbVzs3S5JxBj LaMg== X-Gm-Message-State: AOJu0YzItsrGLT03Ek++fcwYtGmyqsCXbqbyK3kIYIXHlgALOkqA9TIS saIcJ4Ro4oQNFjMPmnT8D8/1sXLsGS4RgaEMePWPzdAHwZO9luEga/qxdakspZ3tFFdnccDqii+ tBHhyLD8tV9yrA+iCVRFTHWR08HbbYzeZfPS028LQAzQcn2CU6Hf+SKkoHTG+nkYvIVCzs/Q8S/ p7pzuE8R+osEJCziBnAIgRinleZMyy1icpbtXWiiGLg0SEfNw= X-Gm-Gg: AeBDiesGmGeF0k2mLFEdY2DnbdcVSp70jbZaXoLPdv2lcLkTyABmkWKMff3TQomDZyn /CfBPmkg7pNkK26NAMpsBVZoCag3i/yhmFlY7WoHhDOSLAsSA0W7rJ0535UfcgpUHSicQH32CrK F41lYG9eNeIz8776+FcfIn7SvvT3+bI1vji+jsG2pblTQ3M0eZYkkNG93Vast7mVxNyHgBBdpsF ae5RQ7yVdgIjOOYbE7vGwDyftE73MPIZGRp7aFS94JujkoWBKyN6FZXV68L84sjuQ0VMOlmfvXU c/6dvUiSaaH00lgvNJrsDHwOfwX1r0pcmYTUymcGaWaxnrEVOKhffsH9CAky2iZknMiz3np15DF Bn9aY9qqAgPy0USOQpjBhmG5DJlU= X-Received: by 2002:a05:600c:19ce:b0:489:1c32:210d with SMTP id 5b1f17b1804b1-48a8eb8834fmr52977215e9.15.1777645382957; Fri, 01 May 2026 07:23:02 -0700 (PDT) X-Received: by 2002:a05:600c:19ce:b0:489:1c32:210d with SMTP id 5b1f17b1804b1-48a8eb8834fmr52976335e9.15.1777645382284; Fri, 01 May 2026 07:23:02 -0700 (PDT) Received: from localhost ([31.111.84.232]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-48a8eb69698sm111768325e9.1.2026.05.01.07.23.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2026 07:23:01 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 3/6] gdb/tui: prevent TUI activation from a secondary prompt Date: Fri, 1 May 2026 15:22:53 +0100 Message-Id: <3b444291c235f24a4fdf34740293333270985745.1777645161.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: sIbwsk9VdeZKNdMW13d-zbvSzAyZ9z4YT2QN2DIuBSM_1777645383 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit content-type: text/plain; charset="US-ASCII"; x-default=true X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org The TUI can be activated with key combinations like 'C-x C-a'. This is handled by readline calling the function tui_rl_switch_mode, or various other functions which indirectly call that function. These multi-key combinations can be used even at a secondary prompt, e.g. the: Make breakpoint pending on future shared library load? (y or [n]) The problem with this is that when the TUI activates CLI content doesn't carry over into the `cmd` window, so the secondary prompt is not visible to the user after the mode switch. Worse, because the content doesn't carry over we clear the readline state, and this involves sending a '\n' to readline. This newline will select the default action at the secondary prompt, which might not be what the user actually wants. Now, we could imagine trying to "fix" this so that the CLI content is copied over into the `cmd` window, and the secondary prompt is represented to the user, so they can then make the choice they want, but implementing this fix would be a big job, for very little gain. Easier I think, to just prevent the user switching to TUI mode while at a secondary prompt. I created a new templated wrapper function tui_rl_keybinding, which is then used to wrap every function that is bound to a readline multi-key combination. The wrapper function checks if we are in a secondary prompt, and if we are, performs an early return. For completeness, I've added an assert that we are not in a secondary prompt to all of the wrapped functions, this (hopefully) will help catch cases where these functions are called directly without going through the wrapper. There's a new helper proc added to lib/gdb.exp, this will be used by additional tests later in this series. The user can still switch to TUI mode at the primary '(gdb)' prompt. --- .../gdb.tui/activate-from-secondary-prompt.c | 22 +++ .../activate-from-secondary-prompt.exp | 154 ++++++++++++++++++ gdb/testsuite/lib/gdb.exp | 28 ++++ gdb/tui/tui.c | 73 ++++++--- 4 files changed, 255 insertions(+), 22 deletions(-) create mode 100644 gdb/testsuite/gdb.tui/activate-from-secondary-prompt.c create mode 100644 gdb/testsuite/gdb.tui/activate-from-secondary-prompt.exp diff --git a/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.c b/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.c new file mode 100644 index 00000000000..6a0e311ef41 --- /dev/null +++ b/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2026 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.exp b/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.exp new file mode 100644 index 00000000000..8de044e7b19 --- /dev/null +++ b/gdb/testsuite/gdb.tui/activate-from-secondary-prompt.exp @@ -0,0 +1,154 @@ +# Copyright 2026 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Check that the TUI can NOT be activated using 'C-x C-a', and similar +# key combinations, from a secondary prompt. Activating from the +# secondary prompt has the same effect as pressing 'Return' at the +# prompt, which might not be what the user wants. +# +# We could imagine a world where, when activating the TUI from a +# secondary prompt works as we might expect, the prompt is not +# cancelled, but reprinted within the TUI, and the user can then make +# their choice and continue with their debug session. If we ever +# implement this, then this test will need to change. +# +# For now though we take the easy way and just ban the user from +# activating the TUI from a secondary prompt. + +load_lib debuginfod-support.exp + +tuiterm_env + +require allow_tui_tests + +standard_testfile + +if {[build_executable "build executable" ${testfile} ${srcfile}] == -1} { + return +} + +# Check that readline is in use. +clean_restart +if { ![readline_is_used] } { + unsupported "readline is required" + return +} + +# Assuming that GDB is at a secondary prompt, try various multi-key +# combinations and check that the screen doesn't change, these should +# all be ignored. +proc test_multi_key_combos {} { + foreach mk { \030\001 \030a \030A \0302 \0301 \030o \030s } { + set before [Term::get_region 0 0 80 24 "\r\n"] + send_gdb $mk + set after [Term::get_region 0 0 80 24 "\r\n"] + + gdb_assert { $before eq $after } \ + "no changes after sending '[unprintable_to_octal $mk]'" + } +} + +# Send CHAR followed by a newline to GDB, this should quit the +# currently active secondary prompt. Wait for the GDB prompt to +# present, then send a basic print command to GDB to ensure that GDB +# is still interactive. +proc quit_prompt { char } { + send_gdb "${char}\n" + Term::wait_for "" + + gdb_test "print 1" " = 1" +} + +# Trigger the pagination prompt, then check that the multi-key +# combinations don't result in a change to TUI mode. Finally, check +# that GDB is still responsive. +proc_with_prefix test_from_pager_prompt {} { + Term::clean_restart 24 80 $::testfile + + set cmd "echo " + for { set i 0 } { $i < 100 } { incr i } { + set cmd "${cmd}${i}\\n" + } + + gdb_test_no_output "set pagination on" + gdb_test_no_output "set height 24" + send_gdb "$cmd\n" + + if {![Term::wait_for_region_contents 0 0 80 24 \ + [string_to_regexp $::pagination_prompt_str]]} { + fail "spot secondary prompt" + return + } + + test_multi_key_combos + quit_prompt q +} + +# Trigger the debuginfod prompt, then check that the multi-key +# combinations don't result in a change to TUI mode. Finally, check +# GDB is still responsive. +proc_with_prefix test_from_debuginfod_prompt {} { + if { ![allow_debuginfod_tests] } { + return + } + + set stripped_binfile [standard_output_file ${::testfile}-stripped] + file copy -force $::binfile $stripped_binfile + if {[gdb_gnu_strip_debug $stripped_binfile no-debuglink]} { + unsupported "produce separate debug info for [file tail $stripped_binfile]" + return + } + + if {[section_get $stripped_binfile ".gnu_debuglink"] ne ""} { + unsupported "debug information has already been split out" + return + } + + save_vars { env(DEBUGINFOD_URLS) } { + setenv DEBUGINFOD_URLS "foo" + Term::clean_restart 24 80 + } + + send_gdb "file \"$stripped_binfile\"\n" + if {![Term::wait_for_region_contents 0 0 80 24 \ + [string_to_regexp {(y or [n]) }]]} { + fail "spot secondary prompt" + return + } + + test_multi_key_combos + quit_prompt n +} + +# Trigger the pending breakpoint prompt, then check that the multi-key +# combinations don't result in a change to TUI mode. Finally, check +# that GDB is still responsive. +proc_with_prefix test_from_breakpoint_prompt {} { + Term::clean_restart 24 80 $::testfile + + send_gdb "break _a_function_that_hopefully_doesnt_exist_\n" + if {![Term::wait_for_region_contents 0 0 80 24 \ + [string_to_regexp {(y or [n]) }]]} { + fail "spot secondary prompt" + return + } + + test_multi_key_combos + quit_prompt n +} + +test_from_pager_prompt +test_from_debuginfod_prompt +test_from_breakpoint_prompt diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 28709004570..d777b25e45c 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -11808,6 +11808,34 @@ proc dwz_version_at_least { ver } { return [version_compare [split $ver .] <= [dwz_version]] } +# Take a string containing unprintable characters and return a string +# with the unprintable characters represented as 3 octal bytes, +# e.g. "\030". +# +# To avoid having to escape backslashes, backslashes themselves are +# also represented as octal. Probably best not to use this for +# strings containing backslashes. +proc unprintable_to_octal { input_string } { + set result "" + + foreach char [split $input_string ""] { + # Convert character to its integer ASCII value. + scan $char %c ascii_val + + # Include printable characters as literals. Exclude backslash + # to avoid needing to escape it, we don't actually expect to + # see that in INPUT_STRING though. + if {[string is print $char] && $char ne "\\"} { + append result $char + } else { + # Include non-printable characters as a 3-digit octal. + append result [format "\\%03o" $ascii_val] + } + } + + return $result +} + require {tcl_version_at_least 8 6 2} # Always load compatibility stuff. diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c index ba4f6f68769..d2e9c1b4def 100644 --- a/gdb/tui/tui.c +++ b/gdb/tui/tui.c @@ -114,6 +114,7 @@ static Keymap tui_readline_standard_keymap; static int tui_rl_switch_mode (int notused1 = 0, int notused2 = 0) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); /* Don't let exceptions escape. We're in the middle of a readline callback that isn't prepared for that. */ @@ -198,6 +199,8 @@ tui_try_activate () static int tui_rl_change_windows (int notused1, int notused2) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); + if (tui_try_activate ()) tui_next_layout (); @@ -209,6 +212,8 @@ tui_rl_change_windows (int notused1, int notused2) static int tui_rl_delete_other_windows (int notused1, int notused2) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); + if (tui_try_activate ()) tui_remove_some_windows (); @@ -220,6 +225,8 @@ tui_rl_delete_other_windows (int notused1, int notused2) static int tui_rl_other_window (int count, int key) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); + if (tui_try_activate ()) tui_set_win_focus_to (tui_next_win (tui_win_with_focus ())); @@ -231,10 +238,10 @@ tui_rl_other_window (int count, int key) static int tui_rl_command_key (int count, int key) { - int i; + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); reinitialize_more_filter (); - for (i = 0; tui_commands[i].cmd; i++) + for (int i = 0; tui_commands[i].cmd; i++) { if (tui_commands[i].key == key) { @@ -262,6 +269,7 @@ tui_rl_command_key (int count, int key) static int tui_rl_command_mode (int count, int key) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); tui_set_key_mode (TUI_ONE_COMMAND_MODE); return rl_insert (count, key); } @@ -271,6 +279,8 @@ tui_rl_command_mode (int count, int key) static int tui_rl_next_keymap (int notused1, int notused2) { + gdb_assert (!gdb_in_secondary_prompt_p (current_ui)); + if (!tui_try_activate ()) return 0; @@ -310,6 +320,20 @@ tui_set_key_mode (enum tui_key_mode mode) tui_show_status_content (); } +/* Wrapper around function FPTR, used to add common checks before + functions that are bound to readline multi-key combinations. */ + +template +int +tui_rl_keybinding (int count, int key) +{ + /* Don't allow TUI changes while we're at an interactive prompt. */ + if (gdb_in_secondary_prompt_p (current_ui)) + return 0; + + return FPTR (count, key); +} + /* Initialize readline and configure the keymap for the switching key shortcut. */ void @@ -324,11 +348,16 @@ tui_ensure_readline_initialized () int i; Keymap tui_ctlx_keymap; - rl_add_defun ("tui-switch-mode", tui_rl_switch_mode, -1); - rl_add_defun ("next-keymap", tui_rl_next_keymap, -1); - rl_add_defun ("tui-delete-other-windows", tui_rl_delete_other_windows, -1); - rl_add_defun ("tui-change-windows", tui_rl_change_windows, -1); - rl_add_defun ("tui-other-window", tui_rl_other_window, -1); + rl_add_defun ("tui-switch-mode", + tui_rl_keybinding, -1); + rl_add_defun ("next-keymap", + tui_rl_keybinding, -1); + rl_add_defun ("tui-delete-other-windows", + tui_rl_keybinding, -1); + rl_add_defun ("tui-change-windows", + tui_rl_keybinding, -1); + rl_add_defun ("tui-other-window", + tui_rl_keybinding, -1); tui_keymap = rl_make_bare_keymap (); @@ -361,21 +390,21 @@ tui_ensure_readline_initialized () rl_bind_key_in_map (i, tui_rl_command_mode, tui_keymap); } - rl_bind_key_in_map ('a', tui_rl_switch_mode, emacs_ctlx_keymap); - rl_bind_key_in_map ('a', tui_rl_switch_mode, tui_ctlx_keymap); - rl_bind_key_in_map ('A', tui_rl_switch_mode, emacs_ctlx_keymap); - rl_bind_key_in_map ('A', tui_rl_switch_mode, tui_ctlx_keymap); - rl_bind_key_in_map (c_ctrl ('A'), tui_rl_switch_mode, emacs_ctlx_keymap); - rl_bind_key_in_map (c_ctrl ('A'), tui_rl_switch_mode, tui_ctlx_keymap); - rl_bind_key_in_map ('1', tui_rl_delete_other_windows, emacs_ctlx_keymap); - rl_bind_key_in_map ('1', tui_rl_delete_other_windows, tui_ctlx_keymap); - rl_bind_key_in_map ('2', tui_rl_change_windows, emacs_ctlx_keymap); - rl_bind_key_in_map ('2', tui_rl_change_windows, tui_ctlx_keymap); - rl_bind_key_in_map ('o', tui_rl_other_window, emacs_ctlx_keymap); - rl_bind_key_in_map ('o', tui_rl_other_window, tui_ctlx_keymap); - rl_bind_key_in_map ('q', tui_rl_next_keymap, tui_keymap); - rl_bind_key_in_map ('s', tui_rl_next_keymap, emacs_ctlx_keymap); - rl_bind_key_in_map ('s', tui_rl_next_keymap, tui_ctlx_keymap); + rl_bind_key_in_map ('a', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('a', tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map ('A', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('A', tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map (c_ctrl ('A'), tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map (c_ctrl ('A'), tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map ('1', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('1', tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map ('2', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('2', tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map ('o', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('o', tui_rl_keybinding, tui_ctlx_keymap); + rl_bind_key_in_map ('q', tui_rl_keybinding, tui_keymap); + rl_bind_key_in_map ('s', tui_rl_keybinding, emacs_ctlx_keymap); + rl_bind_key_in_map ('s', tui_rl_keybinding, tui_ctlx_keymap); /* Initialize readline after the above. */ rl_initialize (); -- 2.25.4