Search code examples
pythonpython-3.xcurses

Differentiate between ^J and <Enter> in curses


I've noticed some curses applications (for instance vim) treat ^J and <Enter> as the same keypress

I've also noticed that others treat them as separate keys (for instance nano which uses ^J for "Justify")

In my particular case, I'm using curses through python, however both presses appear to give the same value

Here's a small demo application:

import curses


def c_main(stdscr):
    wch = ''
    while wch != 'q':
        stdscr.addstr(0, 0, 'Press a key, q to quit: ')
        wch = stdscr.get_wch()
        key = wch if isinstance(wch, int) else ord(wch)
        keyname = curses.keyname(key)
        stdscr.insstr(1, 0, f'> got {wch!r} {key!r} {keyname!r}{" " * 80}')


def main():
    curses.wrapper(c_main)


if __name__ == '__main__':
    exit(main())

For both ^J (control + J) and <enter> (enter key) I get the following:

Press a key, q to quit: 
> got '\n' 10 b'^J'

How can I differentiate these two?


Solution

  • Setting curses.nonl() disables translation of the <enter> key to '\n'

    For example:

    import curses
    
    
    def c_main(stdscr):
        curses.nonl()
        wch = ''
        i = 1
        while wch != 'q':
            stdscr.addstr(0, 0, 'Press a key, q to quit: ')
            stdscr.keypad(False)
            wch = stdscr.get_wch()
            key = wch if isinstance(wch, int) else ord(wch)
            keyname = curses.keyname(key)
            stdscr.insstr(i, 0, f'> got {wch!r} {key!r} {keyname!r}{" " * 80}')
            i += 1
    
    
    def main():
        curses.wrapper(c_main)
    

    And then issuing ^J followed by <enter>:

    Press a key, q to quit: 
    > got '\n' 10 b'^J'
    > got '\r' 13 b'^M'