What are the `y` and `x` params to the python curses `window.getch()` method?

228 Views Asked by At

I may be missing something very obvious, but I am confused by the optional [y, x] parameters to the window.getch( [y, x] ) method described in the Python documentation. What are these optional params for, and what do they do if I include them in my call?

As far as I can tell the documentation doesn't mention what these parameters are for. It just says:

Get a character. Note that the integer returned does not have to be in ASCII range: function keys, keypad keys and so on are represented by numbers higher than 255. In no-delay mode, return -1 if there is no input, otherwise wait until a key is pressed.

The window.get_wch( [y, x] ) and window.getkey( [y, x] ) methods seem to have similarly undescribed optional [y, x] params.

3

There are 3 best solutions below

2
Wandering Logic On BEST ANSWER

I had to go to the old curses library man pages to find an answer. The extra arguments move the cursor to the specified position. The thing I didn't realize is that these methods are not always just reading keyboard input. They can also modify the screen state, which is not at all obvious from the documentation. In the (not typically used) echo mode, these curses functions echo the keyboard input back to the screen.

Older versions of the curses man page for example, say:

Unless noecho has been set, then the character will also be echoed into the designated window according to the following rules: If the character is the current erase character, left arrow, or backspace, the cursor is moved one space to the left and that screen position is erased as if delch had been called. If the character value is any other KEY_ define, the user is alerted with a beep call. Otherwise the character is simply output to the screen.

And then the netbsd man page for https://man.netbsd.org/curses_input.3 further describes the behavior of the mvgetch() function as:

The mvgetch() and mvwgetch() functions are the same as the getch() and wgetch() functions, respectively, excepting that wmove() is called to move the cursor to the position specified by y, x before the character is read.

So, if noecho is unset, then the Python getch() method with no params calls the C getch() function, and the key read from the keyboard is echoed at the current screen location. If the Python getch( y, x ) method is called with the optional y and x params, then the C mvgetch( y, x) function is invoked, which moves the cursor to y, x, and then does getch().

Here is the code for _curses_window_getch_impl() in the curses Module of the cpython interpreter where we can see that that wgetch() or mvwgetch() are getting called depending on whether the optional params are provided: https://github.com/python/cpython/blob/main/Modules/_cursesmodule.c#L1401

1
Solomon Ucko On

https://docs.python.org/3/howto/curses.html#windows-and-pads

Note that the coordinate system used in curses is unusual. Coordinates are always passed in the order y,x, and the top-left corner of a window is coordinate (0,0). This breaks the normal convention for handling coordinates where the x coordinate comes first. This is an unfortunate difference from most other computer applications, but it’s been part of curses since it was first written, and it’s too late to change things now.

Your application can determine the size of the screen by using the curses.LINES and curses.COLS variables to obtain the y and x sizes. Legal coordinates will then extend from (0,0) to (curses.LINES - 1, curses.COLS - 1).

https://docs.python.org/3/library/curses.html

Note: Whenever x or y arguments to a function or a method are optional, they default to the current cursor location. Whenever attr is optional, it defaults to A_NORMAL.

https://docs.python.org/3/library/curses.html#curses.getsyx

Return the current coordinates of the virtual screen cursor as a tuple (y, x). If leaveok is currently True, then return (-1, -1).

https://docs.python.org/3/library/curses.html#curses.window.addch

Paint character ch at (y, x) with attributes attr, overwriting any character previously painted at that location. By default, the character position and attributes are the current settings for the window object.

https://docs.python.org/3/howto/curses.html#displaying-text

Move to position y,x within the window

Windows remember where the cursor was left after the last operation, so if you leave out the y,x coordinates, the string or character will be displayed wherever the last operation left off. You can also move the cursor with the move(y,x) method.

0
Thomas Dickey On

Python's curses binding is based on the underlying curses API, without (for example) generalizing windows and pads into an true object-programming model. The y,x come from the curses API, which uses different function names for the versions with/without these parameters. Referring to the ncurses getch manpage:

int getch(void);
int wgetch(WINDOW *win);
int mvgetch(int y, int x);
int mvwgetch(WINDOW *win, int y, int x);

The main ncurses manpage explains the parameters:

The routines prefixed with mv require a y and x coordinate to move to before performing the appropriate action. The mv routines imply a call to move before the call to the other routine. The coordinate y always refers to the row (of the window), and x always refers to the column. The upper left-hand corner is always (0,0), not (1,1).

Like the ncurses manpages, the Python curses documentation has a "main" part, which is the tutorial Curses Programming with Python. That outlines the way these optional parameters are used (overloading the names):

From a C programmer’s point of view, curses may sometimes look like a twisty maze of functions, all subtly different. For example, addstr() displays a string at the current cursor location in the stdscr window, while mvaddstr() moves to a given y,x coordinate first before displaying the string. waddstr() is just like addstr(), but allows specifying a window to use instead of using stdscr by default. mvwaddstr() allows specifying both a window and a coordinate.

Fortunately the Python interface hides all these details. stdscr is a window object like any other, and methods such as addstr() accept multiple argument forms. Usually there are four different forms.

Unlike most graphical systems (which use the horizontal ordinate x first), curses uses the vertical ordinate y first. That probably came about from dealing with hardware terminals (more than 90% of the entries in the terminal database use row,column order for cursor-addressing). However, the low-level terminfo and termcap function tgoto is inconsistent with the high-level curses functions:

Doing this shows a quirk in tgoto: most hardware terminals use cursor addressing with row first, but the original developers of the termcap interface chose to put the column parameter first. The tgoto function swaps the order of parameters. It does this also for calls requiring only a single parameter. In that case, the first parameter is merely a placeholder.