about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSören Tempel <soeren+git@soeren-tempel.net>2021-05-22 01:20:11 +0200
committerSören Tempel <soeren+git@soeren-tempel.net>2021-05-22 01:20:11 +0200
commitedcd59be26015cd971b9f09d092c74087c8d8a33 (patch)
treea22e4a09238d9a831a533c3e231b3146d21fa5d3
parente457cd88660512e6744fa75a1cc34d6d0b5f1358 (diff)
Generalize support for termios-keybindings
-rw-r--r--saneterm/input.py15
-rw-r--r--saneterm/terminal.py16
-rw-r--r--saneterm/termview.py12
3 files changed, 30 insertions, 13 deletions
diff --git a/saneterm/input.py b/saneterm/input.py
index 7ca3e54..29658c3 100644
--- a/saneterm/input.py
+++ b/saneterm/input.py
@@ -10,7 +10,6 @@ class KeyBindings():
             bind "<ctrl>u" { "kill-after-output" () };
             bind "<ctrl>a" { "move-input-start" () };
             bind "<ctrl>e" { "move-input-end" () };
-            bind "<ctrl>c" { "interrupt" () };
         }
 
         * {
@@ -18,11 +17,21 @@ class KeyBindings():
         }
     """
 
-    def __init__(self):
+    def __init__(self, widget):
         self.provider = Gtk.CssProvider()
         self.provider.load_from_data(self.stylesheet)
 
-    def apply(self, widget):
         style_ctx = widget.get_style_context()
         style_ctx.add_provider(self.provider,
                 Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
+
+    def add_bind(self, key, signal, arg):
+        bindings = self.__binding_set()
+        # Using Gtk.BindingEntry.add_signall() would be preferable
+        # https://gitlab.gnome.org/GNOME/pygobject/-/issues/474
+        Gtk.BindingEntry().add_signal_from_string(bindings,
+                F'bind "{key}" {{ "{signal}" ({arg}) }};')
+
+    def __binding_set(self):
+        return Gtk.BindingSet.find("saneterm-key-bindings")
+
diff --git a/saneterm/terminal.py b/saneterm/terminal.py
index 8e929de..bc19a88 100644
--- a/saneterm/terminal.py
+++ b/saneterm/terminal.py
@@ -11,6 +11,7 @@ import gi
 gi.require_version("Gtk", "3.0")
 
 from gi.repository import Gtk
+from gi.repository import Gdk
 from gi.repository import GLib
 
 NAME = "saneterm"
@@ -64,11 +65,11 @@ class Terminal(Gtk.Window):
         # Block-wise reading from the PTY requires an incremental decoder.
         self.decoder = codecs.getincrementaldecoder('UTF-8')()
 
-        bindings = input.KeyBindings()
-        bindings.apply(self.termview)
-
         self.termview.connect("new-user-input", self.user_input)
-        self.termview.connect("interrupt", self.interrupt)
+        self.termview.connect("termios-ctrlkey", self.termios_ctrl)
+
+        bindings = input.KeyBindings(self.termview)
+        bindings.add_bind("<ctrl>c", "termios-ctrlkey", termios.VINTR)
 
         self.add(self.termview)
 
@@ -88,10 +89,11 @@ class Terminal(Gtk.Window):
     def user_input(self, termview, line):
         os.write(self.pty.master, line.encode("UTF-8"))
 
-    def interrupt(self, termview):
+    def termios_ctrl(self, termview, cidx):
+        # TODO: Employ some heuristic to cache tcgetattr result.
         cc = termios.tcgetattr(self.pty.master)[-1]
-        os.write(self.pty.master, cc[termios.VINTR])
+        os.write(self.pty.master, cc[cidx])
 
         # XXX: Clear line-based buffer here (i.e. update the
         # marks in TermView) in case the application doesn't
-        # write anything to the PTY on receiving VINTR.
+        # write anything to the PTY on receiving the CC.
diff --git a/saneterm/termview.py b/saneterm/termview.py
index 079939b..0728a83 100644
--- a/saneterm/termview.py
+++ b/saneterm/termview.py
@@ -21,6 +21,10 @@ class TermView(Gtk.TextView):
     where data from the backend source was last written. While the
     _last_mark constitues the position where user input would be
     added.
+
+    Control characters are not line-buffered. Instead these are
+    intercepted through pre-defined key bindings by Gtk and communicated
+    to the application via the termios-ctrlkey signal.
     """
 
     def __init__(self):
@@ -37,7 +41,6 @@ class TermView(Gtk.TextView):
             "kill-after-output": self.__kill_after_output,
             "move-input-start": self.__move_input_start,
             "move-input-end": self.__move_input_end,
-            "interrupt": None
         }
 
         for signal in signals.items():
@@ -46,8 +49,11 @@ class TermView(Gtk.TextView):
                     GObject.SIGNAL_ACTION, GObject.TYPE_NONE,
                     ())
 
-            if not func is None:
-                self.connect(name, func)
+            self.connect(name, func)
+
+        GObject.signal_new("termios-ctrlkey", self,
+                GObject.SIGNAL_ACTION, GObject.TYPE_NONE,
+                (GObject.TYPE_LONG,))
 
         GObject.signal_new("new-user-input", self,
                 GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE,