I found some hacker ways to achieve the desired behavior using Ctrl-C.
Set use_rawinput=False and replace stdin
This file attaches (more or less ...) to the common cmd.Cmd interface. Unfortunately, this disables readline support.
You can set use_rawinput to false and pass another file-like object to replace stdin in Cmd.__init__() . In practice, only readline() is called for this object. Thus, you can create a wrapper for stdin that catches KeyboardInterrupt and performs the required behavior:
class _Wrapper: def __init__(self, fd): self.fd = fd def readline(self, *args): try: return self.fd.readline(*args) except KeyboardInterrupt: print() return '\n' class TestShell(cmd.Cmd): def __init__(self): super().__init__(stdin=_Wrapper(sys.stdin)) self.use_rawinput = False self.prompt = '$ ' def precmd(self, line): if line == 'EOF': return 'exit' return line def emptyline(self): pass def do_exit(self, line): return True TestShell().cmdloop()
When I run this on my terminal, Ctrl-C displays ^C and switches to a new line.
Monkey-patch input()
If you want input() results, except that you want different behavior for Ctrl-C, one way to do this would be to use a different function instead of input() :
def my_input(*args):
However, if you just blindly set input = my_input , you will get infinite recursion because my_input() will call input() , which is now itself. But this is a fix, and you can fix the __builtins__ dictionary in the cmd module to use your modified input() method during Cmd.cmdloop() :
def input_swallowing_interrupt(_input): def _input_swallowing_interrupt(*args): try: return _input(*args) except KeyboardInterrupt: print('^C') return '\n' return _input_swallowing_interrupt class TestShell(cmd.Cmd): def cmdloop(self, *args, **kwargs): old_input_fn = cmd.__builtins__['input'] cmd.__builtins__['input'] = input_swallowing_interrupt(old_input_fn) try: super().cmdloop(*args, **kwargs) finally: cmd.__builtins__['input'] = old_input_fn
Note that this modifies input() for all cmd objects , not just TestShell objects. If this is unacceptable to you, you can ...
Copy the source of Cmd.cmdloop() and change it
Since you subclass it, you can make cmdloop() do anything. "Everything you want" may include copying parts of Cmd.cmdloop() and rewriting others. Either replace the call with input() calling another function, or catch and process KeyboardInterrupt right there in your rewritten cmdloop() .
If you are afraid that the base implementation will change with new versions of Python, you can copy the entire cmd module into a new module and change what you want.