Subject: bug#22743: 25.0.91: set-quit-char does not work if emacs lacks a controlling tty

From: Duncan Burke <[email-masked]>
Date: Sat, 20 Feb 2016 16:31:54 +1100

I have heavily customised keybindings on a dvorak layout and this 
necessitates
rebinding quit away from its default value of C-g.

I have rebound C-g in keymaps where it is already defined (such as 
global-map,
minibuffer-local-map and query-replace-map), and have found this to work in
most cases with one major issue in flyspell-mode.

flyspell-post-command-hook calls flyspell-check-word-p, which calls sit-for,
which ultimately calls read_char in keyboard.c.

quit_char in keyboard.c is by default set to ?\C-g and as a consequence in
flyspell-mode if C-g is pressed immediately after entering some text a 
quit is
signalled rather than running the command bound to C-g.

set-quit-char should be able to change quit_char to my desired value of 
?\C-p,
however I run emacs in a graphical window and set-quit-char silently does
nothing if emacs does not have a controlling tty.

To reproduce this issue in emacs 25.0.91.7 with emacs -Q in a graphical
window:

(define-key global-map [?\C-g] 'backward-delete-char)
(define-key global-map [?\C-p] 'keyboard-quit)
(set-quit-char ?\C-p)

;; observe that quit_char is unchanged from original value of ?\C-g
(current-input-mode)

By running flyspell mode, typing something and pressing C-g it can be 
observed
that backward-delete-char is not run as would be expected.

I have attached a patch that changes the behaviour of set-quit-char so that
quit_char is set even if emacs does not have a controlling tty.
>From e33022f19c91012a9f2f158daa9e29cc2fbb79c5 Mon Sep 17 00:00:00 2001
From: Duncan Burke <[email-masked]>
Date: Sat, 20 Feb 2016 00:33:58 +1100
Subject: [PATCH] Fix set-quit-char when there's no controlling tty

set-quit-char currently does nothing if get_named_terminal("/dev/tty")
is NULL. However it is useful to be able to set quit_char when in a
graphical window as this allows it to be bound to something other than
C-g in an alternate keybinding setup.

This patch allows quit_char to be set when there is no controlling
tty. quit_char is masked to 7 bits as the 8th bit is not used for the
meta modifier in X.
---
 src/keyboard.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/src/keyboard.c b/src/keyboard.c
index 546c012..f3ce4b1 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -10557,24 +10557,29 @@ See also `current-input-mode'.  */)
   struct terminal *t = get_named_terminal ("/dev/tty");
   struct tty_display_info *tty;
 
-  if (!t)
-    return Qnil;
-  tty = t->display_info.tty;
-
   if (NILP (quit) || !INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400)
     error ("QUIT must be an ASCII character");
 
+  if (t)
+    {
+      tty = t->display_info.tty;
 #ifndef DOS_NT
-  /* this causes startup screen to be restored and messes with the mouse */
-  reset_sys_modes (tty);
+      /* this causes startup screen to be restored and messes with the mouse */
+      reset_sys_modes (tty);
 #endif
 
-  /* Don't let this value be out of range.  */
-  quit_char = XINT (quit) & (tty->meta_key == 0 ? 0177 : 0377);
+      /* Don't let this value be out of range.  */
+      quit_char = XINT (quit) & (tty->meta_key == 0 ? 0177 : 0377);
 
 #ifndef DOS_NT
-  init_sys_modes (tty);
+      init_sys_modes (tty);
 #endif
+    }
+  else
+    {
+      /* No associated TTY, accept 7-bit ASCII characters */
+      quit_char = XINT (quit) & 0177;
+    }
 
   return Qnil;
 }
-- 
2.7.0