Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Doc/library/curses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,37 @@ The module :mod:`!curses` defines the following functions:
a key with that value.


.. function:: define_key(definition, keycode)

Define an escape sequence *definition*, a string, as a key that generates
the key code *keycode*, so that :mod:`curses` interprets it like one of the
keys predefined in the terminal database.

If *definition* is ``None``, any existing binding for *keycode* is removed.
If *keycode* is zero or negative, any existing binding for *definition* is
removed.

.. versionadded:: next


.. function:: key_defined(definition)

Return the key code bound to the escape sequence *definition*, a string,
``0`` if no key code is bound to it, or ``-1`` if *definition* is a prefix
of a longer bound sequence (and so is ambiguous).

.. versionadded:: next


.. function:: keyok(keycode, enable)

Enable (if *enable* is true) or disable (otherwise) interpretation of the
key code *keycode*. Unlike :meth:`window.keypad`, this affects a single
key code rather than all of them.

.. versionadded:: next


.. function:: halfdelay(tenths)

Used for half-delay mode, which is similar to cbreak mode in that characters
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ curses
:func:`~curses.scr_set`, which dump the whole screen to a file and restore it.
(Contributed by Serhiy Storchaka in :gh:`152260`.)

* Add the :mod:`curses` key-management functions :func:`~curses.define_key`,
:func:`~curses.key_defined` and :func:`~curses.keyok`, available when built
against an ncurses with ``NCURSES_EXT_FUNCS``.
(Contributed by Serhiy Storchaka in :gh:`152334`.)

gzip
----

Expand Down
15 changes: 15 additions & 0 deletions Lib/test/test_curses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,21 @@ def test_env_queries(self):
self.assertIsInstance(c, str)
self.assertEqual(len(c), 1)

@requires_curses_func('define_key')
def test_key_management(self):
# Bind a custom escape sequence to a free key code and read it back.
seq = '\x1bspam'
keycode = 0o600
curses.define_key(seq, keycode)
self.assertEqual(curses.key_defined(seq), keycode)
# keyok enables or disables interpretation of a single key code.
# Use the key code just defined, which is guaranteed to be known.
self.assertIsNone(curses.keyok(keycode, False))
self.assertIsNone(curses.keyok(keycode, True))
# Passing None removes the binding for the key code.
curses.define_key(None, keycode)
self.assertEqual(curses.key_defined(seq), 0)

def test_output_options(self):
stdscr = self.stdscr

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add the :func:`curses.define_key`, :func:`curses.key_defined` and
:func:`curses.keyok` key-management functions.
74 changes: 74 additions & 0 deletions Modules/_cursesmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5776,6 +5776,77 @@ _curses_has_key_impl(PyObject *module, int key)
}
#endif

#if defined(NCURSES_EXT_FUNCS) && NCURSES_EXT_FUNCS
/*[clinic input]
_curses.define_key

definition: str(accept={str, NoneType})
Escape sequence to bind, or None to remove a binding.
keycode: int
Key code to generate.
/

Define an escape sequence for a key code.

If definition is None, any existing binding for keycode is removed.
If keycode is zero or negative, the binding for definition is removed.
[clinic start generated code]*/

static PyObject *
_curses_define_key_impl(PyObject *module, const char *definition,
int keycode)
/*[clinic end generated code: output=9dc655653bb09062 input=8db9e0d8802c709f]*/
{
PyCursesStatefulInitialised(module);

return curses_check_err(module, define_key(definition, keycode),
"define_key", NULL);
}

/*[clinic input]
_curses.key_defined

definition: str
Escape sequence.
/

Return the key code bound to an escape sequence.

Return 0 if no key code is bound to the escape sequence, or -1 if the
escape sequence is a prefix of another bound sequence (so ambiguous).
[clinic start generated code]*/

static PyObject *
_curses_key_defined_impl(PyObject *module, const char *definition)
/*[clinic end generated code: output=2d357e01fe277c88 input=03749d7bd79d8d2c]*/
{
PyCursesStatefulInitialised(module);

return PyLong_FromLong(key_defined(definition));
}

/*[clinic input]
_curses.keyok

keycode: int
Key code.
enable: bool
Whether the key code is interpreted.
/

Enable or disable interpretation of an individual key code.
[clinic start generated code]*/

static PyObject *
_curses_keyok_impl(PyObject *module, int keycode, int enable)
/*[clinic end generated code: output=43eab0b4d9973e44 input=5bee51d850f481b9]*/
{
PyCursesStatefulInitialised(module);

return curses_check_err(module, keyok(keycode, enable), "keyok", NULL);
}
#endif

/*[clinic input]
_curses.init_color

Expand Down Expand Up @@ -7759,6 +7830,9 @@ static PyMethodDef cursesmodule_methods[] = {
_CURSES_HAS_IC_METHODDEF
_CURSES_HAS_IL_METHODDEF
_CURSES_HAS_KEY_METHODDEF
_CURSES_DEFINE_KEY_METHODDEF
_CURSES_KEY_DEFINED_METHODDEF
_CURSES_KEYOK_METHODDEF
_CURSES_HALFDELAY_METHODDEF
_CURSES_INIT_COLOR_METHODDEF
_CURSES_INIT_PAIR_METHODDEF
Expand Down
169 changes: 168 additions & 1 deletion Modules/clinic/_cursesmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading