[Urwid] Changing interrupt and quit characters (untested low-level code)

Derek Peschel dpeschel at eskimo.com
Sun Jul 23 20:17:00 EDT 2006


Among other goals, I want to make a urwid editor that's more like the
real-world editors out there, while having new features of its own.
For years my real-world editor of choice has been jstar.

http://sourceforge.net/projects/joe-editor

jstar uses ^C for "page down".  On UNIX and with curses_display, urwid
tells the OS it wants to read every character, and tells the OS it wants
to handle the display itself, but those are separate from the setting
that turns off interrupt and quit signals.  And ^C normally sends an
interrupt signal.  In Python that creates a KeyboardInterrupt exception.

This little example keeps the signals on, and demonstrates how to change
the quit character from ^\ to ^^ and the interrupt character from ^C to ^\.
You get 'ctrl c' printouts if it works.  It is totally specific to POSIX
and does a bad job of detecting errors.  I haven't tested it with raw_display
or on any machine besides mine.  If you already have any signal set to ^^,
it will stop working.  If you have any program (telnet or screen, say) that
checks for ^^, Python won't get quit signals unless you have the program
send another ^^.  But my code does two things right, thanks to curses and to
a try/finally block: the changes are undone on exit, undone on suspend, and
redone on resume.

I used the example in section 8.8.1 of the Python Library Reference.

Another approach would turn the signals off, but I wanted the safety
of having them, at least for now.  Another approach would give up one
signal so the application has an extra key to use, but so far I have no
burning need for keys.

-- Derek
-------------- next part --------------
--- urwid-0.9.5/input_test.py	Fri Jul 14 18:26:45 2006
+++ urwid-0.9.5-new/changesignals.py	Sun Jul 23 17:10:55 2006
@@ -27,18 +27,20 @@
 import urwid.raw_display
 import urwid.web_display
 import urwid
+import termios
 
 import sys
 
 try: True # old python?
 except: False, True = 0, 1
-		
+
 if urwid.web_display.is_web_request():
-	Screen = urwid.web_display.Screen
+	sys.exit("Must run with curses display")
 else:
-	if len(sys.argv)>1 and sys.argv[1][:1] == "r":
-		Screen = urwid.raw_display.Screen
-	else:
+## not tested yet
+#	if len(sys.argv)>1 and sys.argv[1][:1] == "r":
+#		Screen = urwid.raw_display.Screen
+#	else:
 		Screen = urwid.curses_display.Screen
 
 class KeyTest:
@@ -50,18 +52,43 @@
 		self.listbox = urwid.ListBox(self.l)
 		listbox = urwid.AttrWrap(self.listbox, 'listbox')
 		self.top = urwid.Frame( listbox, header )
-		
+
 	def main(self):
 		self.ui.register_palette([
-			('header', 'black', 'dark cyan', 'standout'),
-			('key', 'yellow', 'dark blue', 'bold'),
-			('listbox', 'light gray', 'black' ),
+			('header',  'black',      'dark cyan', 'standout'),
+			('key',     'yellow',     'dark blue', 'bold'),
+			('listbox', 'light gray', 'black'),
 			])
-		self.ui.run_wrapper(self.run)
-	
+		termios_cc = 6 # magic index -- not 4 which is position
+		               #  in the C struct
+		termios__POSIX_VDISABLE = '\xff' # signals are set to this
+		                                 #  when they don't corres-
+		                                 #  pond to any char.
+
+		fd = sys.stdin.fileno()
+		oldterm = termios.tcgetattr(fd)
+		oldterm_int = oldterm[termios_cc][termios.VINTR]
+		oldterm_quit = oldterm[termios_cc][termios.VQUIT]
+		if ord(oldterm_int) != 3: # ^C
+			sys.exit("interrupt char isn't ^C")
+		if ord(oldterm_quit) != 28: # ^\
+			sys.exit("quit char isn't ^\\")
+		# no way to check whether applications (telnet, screen)
+		#  are looking for ^^
+		# no check yet for any signals set to ^^
+
+		newterm = termios.tcgetattr(fd)
+		newterm[termios_cc][termios.VQUIT] = chr(30) # ^^
+		newterm[termios_cc][termios.VINTR] = chr(28) # ^\
+		try:
+			termios.tcsetattr(fd, termios.TCSADRAIN, newterm)
+			self.ui.run_wrapper(self.run)
+		finally:
+			termios.tcsetattr(fd, termios.TCSADRAIN, oldterm)
+
 	def run(self):
 		self.ui.set_mouse_tracking()
-		
+
 		cols, rows = self.ui.get_cols_rows()
 
 		keys = ['not q']
@@ -85,24 +112,18 @@
 						") "]
 				else:
 					t += ["'",('key',k),"' "]
-			
+
 			rawt = urwid.Text(", ".join(["%d"%r for r in raw]))
-			
+
 			self.l.append(
 				urwid.Columns([
 					('weight',2,urwid.Text(t)),
 					rawt])
 				)
 			self.listbox.set_focus(len(self.l)-1,'above')
-				
-
 
 def main():
-	urwid.web_display.set_preferences('Input Test')
-	if urwid.web_display.handle_short_request():
-		return
 	KeyTest().main()
-	
 
-if '__main__'==__name__ or urwid.web_display.is_web_request():
+if '__main__' == __name__:
 	main()


More information about the Urwid mailing list