Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why doesn't Python include non-blocking keyboard input function?

8,961 views
Skip to first unread message

jlad...@itu.edu

unread,
Oct 24, 2016, 2:14:17 PM10/24/16
to
After reading this rather vague thread...

https://groups.google.com/forum/#!topic/comp.lang.python/FVnTe2i0UTY

... I find myself asking why Python doesn't include a standard, non-blocking keyboard input function. I have often wanted one myself. The only way that I've ever achieved this behavior is:

1) by restricting the user to pressing Ctrl-C while the program is running, and catching a KeyboardInterrupt; or

2) loading a heavyweight GUI like wxPython or PyQt, and using its event loop to intercept keyboard events.

I gather that non-blocking keyboard input functions aren't the easiest thing to implement. They seem to depend on the operating system. Still, ease of use is a primary goal of Python, and the need for this feature must be common.

Steven D'Aprano

unread,
Oct 25, 2016, 2:39:28 AM10/25/16
to
Not really. I think that lots of people think they need it, but once they write
a little utility, they often realise that it's not that useful. That's just my
opinion, and I'm one of those guys who wrote one:

http://code.activestate.com/recipes/577977-get-single-keypress/?in=user-4172944

Me and ten thousand others.

If you (generic you, not you specifically) are telling the user "press any key
to continue", then you probably shouldn't. *Any* key may not do anything. E.g.
if the user hits the Shift key. A much better interface is to specify a
specific key, and ignore anything else... in which case, why not specify the
Enter key?

raw_input('Press the Enter key to continue... ')


If you are doing something more complex, waiting on different keys to do
different things, then you probably should use an existing text UI like Curses,
or a GUI like wxPython etc, rather than trying to reinvent the wheel badly.



--
Steven
git gets easier once you get the basic idea that branches are homeomorphic
endofunctors mapping submanifolds of a Hilbert space.

BartC

unread,
Oct 25, 2016, 6:02:47 AM10/25/16
to
On 25/10/2016 07:39, Steven D'Aprano wrote:

>> I gather that non-blocking keyboard input functions aren't the easiest thing
>> to implement. They seem to depend on the operating system. Still, ease of
>> use is a primary goal of Python, and the need for this feature must be
>> common.
>
>
> Not really. I think that lots of people think they need it, but once they write
> a little utility, they often realise that it's not that useful.

> If you (generic you, not you specifically) are telling the user "press any key
> to continue", then you probably shouldn't. *Any* key may not do anything. E.g.
> if the user hits the Shift key. A much better interface is to specify a
> specific key, and ignore anything else... in which case, why not specify the
> Enter key?
>
> raw_input('Press the Enter key to continue... ')

Which doesn't work on Python 3. So even here, making it easy by using
line-input, it's not so straightforward.

> If you are doing something more complex, waiting on different keys to do
> different things,

You mean, something as sophisticated as press Enter to continue, or
Escape to quit? Or Page Up and Page Down?

then you probably should use an existing text UI like Curses,
> or a GUI like wxPython etc, rather than trying to reinvent the wheel badly.

But why the need to have to use someone else's massive great wheel? Both
Curses and wxPython are completely over the top IMO for something so
fundamental.

I started coding in 1976 (Christ, 40 years ago!), using teletypes.
Getting line input was easy (apparently easier than in Python now!).
What was hard was:

(1) Reading a single key-press without the user having to press
Enter (or Return as it was then)

(2) Reading that single key-press without the character being echoed to
the output

It seems like little has changed!

You needed this to do what I considered cool things. A bit limited on a
TTY but on a video display, a lot more was possible (editors, games, etc).

As for actually reading from the keyboard, the first board I made that
actually had one (it was gorgeous, with all sorts of exotic keys you
didn't find on typewriters like !, [], {}, + and Ctrl), involved this:

* Poll the byte at some specific port until the top bit changed
from 0 to 1. Then a key had just been pressed.

* The lower 7 bits was the ASCII value of the character (I don't
know what it did about cursor keys, but maybe it didn't have any.)

This gives you the ability to do (2) above. From that, you could do (1)
(echoing) and go on to build full line-orientated input. But you had
complete control.

So, why has it all become so difficult?

--
Bartc

John Pote

unread,
Oct 25, 2016, 6:44:48 AM10/25/16
to
If you are on a windows platform you could use kbhit() from the msvcrt
module as Steven D does in his solution on the activestate site which
also works for xNIX. Worth a look at his code to see how these sort of
things are done on xNIX.

Alternatively you could use a couple of threads. One for your worker
code and one for the keyboard entry code. Use a message queue to pass
received lines from the keyboard thread to the worker thread. OK you
still have to press Enter but you don't need the windows msvcrt library
or xNIX termios modules.

Regards

John


On 25/10/2016 07:39, Steven D'Aprano wrote:

BartC

unread,
Oct 25, 2016, 7:14:51 AM10/25/16
to
On 25/10/2016 11:39, Dennis Lee Bieber wrote:
> On Tue, 25 Oct 2016 11:02:31 +0100, BartC <b...@freeuk.com> declaimed the
> following:
>
>> This gives you the ability to do (2) above. From that, you could do (1)
>> (echoing) and go on to build full line-orientated input. But you had
>> complete control.
>>
>> So, why has it all become so difficult?
>
> Because you now have an interrupt driven operating system with buffered
> line handling between you and the hardware. The OS is handling things like
> back-space/delete, <cr><lf> (from a single keypress -- for those systems
> that use both for line ending), previous line recall/history.
>
> Your polling loop on a status register basically meant nothing else was
> happening on that computer until you retrieved a character

Only if you were specifically waiting for a key press. For the
requirement in the other thread (see link in OP), it just needed to know
if a key had been pressed; that would be very quick (I can't remember if
that status bit latched or not.)

Anyway the next step would have been to wire up the status bit to an
interrupt line.

and passed it on
> to whatever program had requested it. Something doable on a
> single-user/single-task system, but totally at odds with any system running
> a few dozen separate processes.

I don't agree. Each single process shouldn't need to be aware of any of
the others. In the same way that the raw_input() example doesn't need to
take account of the other half-dozen Python programs all waiting on
raw_input() at the same time (which are all waiting for the same keyboard).

> Hardware peripherals are now the domain of the OS, and mere users are
> supposed to request the OS for data... That means OS specific methods for
> bypassing the convenience mode of "cooked" input.

Fine, then let the OS provide the appropriate means if the user program
is not allowed to directly access the hardware. getch() and kbhit() are
crude but they will do for simple programs. But they are not part of the
OS. Implementing the equivalent via calls to Win32 is horrendous (and to
Linux not much better).

(BTW the computer I was using in 1976 had 160 simultaneous users. And
each had their own keyboard. Now usually there is just one keyboard...)

--
bartc

Chris Angelico

unread,
Oct 25, 2016, 7:25:40 AM10/25/16
to
On Tue, Oct 25, 2016 at 9:02 PM, BartC <b...@freeuk.com> wrote:
>> raw_input('Press the Enter key to continue... ')
>
>
> Which doesn't work on Python 3. So even here, making it easy by using
> line-input, it's not so straightforward.

So you use input() instead. Big deal. The concept is still the same.

>> If you are doing something more complex, waiting on different keys to do
>> different things,
>
>
> You mean, something as sophisticated as press Enter to continue, or Escape
> to quit? Or Page Up and Page Down?

Enter to continue or Ctrl-C to quit. Just as easy.

> But why the need to have to use someone else's massive great wheel? Both
> Curses and wxPython are completely over the top IMO for something so
> fundamental.

Fundamental? What exactly is fundamental about key-based input? Much
more fundamental is character-based input, where you request *text*
from the user. How often do you care whether someone pressed '1' on
the top row as compared to '1' on the numeric keypad? How often do you
actually need to handle Backspace as a key, rather than simply having
it remove one character? Do you actually want to distinguish between
typed keys and pasted text? Much more commonly, you simply ask for
input from the user, and get back a line of text. The user might have
edited that line before submitting it, and that's a feature, not a
bug.

When you want more flexibility than "Enter to continue or Ctrl-C to
abort", it probably *is* time to get curses or a GUI toolkit, because
you're doing something that's fundamentally different from "request
text from the user".

ChrisA

Chris Angelico

unread,
Oct 25, 2016, 7:28:30 AM10/25/16
to
On Tue, Oct 25, 2016 at 10:14 PM, BartC <b...@freeuk.com> wrote:
> I don't agree. Each single process shouldn't need to be aware of any of the
> others. In the same way that the raw_input() example doesn't need to take
> account of the other half-dozen Python programs all waiting on raw_input()
> at the same time (which are all waiting for the same keyboard).
>
> Fine, then let the OS provide the appropriate means if the user program is
> not allowed to directly access the hardware. getch() and kbhit() are crude
> but they will do for simple programs. But they are not part of the OS.
> Implementing the equivalent via calls to Win32 is horrendous (and to Linux
> not much better).

There's a huge difference between a loop that calls a blocking
function like (raw_)input and one that calls a non-blocking function
like kbhit(). One of them is polite to other processes; the other is
not. In fact, even in a single-user single-process system, polling is
a bad idea - it means that nothing can go to sleep. Unless, of course,
you want to reimplement the whole concept of blocking calls on top of
non-blocking ones, in which case... why?!?

ChrisA

Marko Rauhamaa

unread,
Oct 25, 2016, 8:10:04 AM10/25/16
to
Chris Angelico <ros...@gmail.com>:

> There's a huge difference between a loop that calls a blocking
> function like (raw_)input and one that calls a non-blocking function
> like kbhit(). One of them is polite to other processes; the other is
> not.

Each process can have its own PTY with a separate virtual keyboard
interface. The main problem is that the Unix terminal interface is quite
old and crude.

I'm guessing the raw inputs come from the /dev/input/* drivers.
Unfortunately the PTYs don't come with their faked /dev/input drivers,
and they would be reserved for root anyway.

> In fact, even in a single-user single-process system, polling is a bad
> idea - it means that nothing can go to sleep.

Yes, spinning is bad. However, there are nicer ways to poll: select,
poll, epoll...

> Unless, of course, you want to reimplement the whole concept of
> blocking calls on top of non-blocking ones, in which case... why?!?

Blocking calls are evil.


Marko

BartC

unread,
Oct 25, 2016, 8:35:38 AM10/25/16
to
On 25/10/2016 12:25, Chris Angelico wrote:
> On Tue, Oct 25, 2016 at 9:02 PM, BartC <b...@freeuk.com> wrote:
>>> raw_input('Press the Enter key to continue... ')
>>
>>
>> Which doesn't work on Python 3. So even here, making it easy by using
>> line-input, it's not so straightforward.
>
> So you use input() instead. Big deal. The concept is still the same.
>
>>> If you are doing something more complex, waiting on different keys to do
>>> different things,
>>
>>
>> You mean, something as sophisticated as press Enter to continue, or Escape
>> to quit? Or Page Up and Page Down?
>
> Enter to continue or Ctrl-C to quit. Just as easy.

Ctrl-C is not the same; that will just abort (without doing proper
termination such as saving your data, or even just asking the user to
confirm).

>
>> But why the need to have to use someone else's massive great wheel? Both
>> Curses and wxPython are completely over the top IMO for something so
>> fundamental.
>
> Fundamental? What exactly is fundamental about key-based input? Much
> more fundamental is character-based input, where you request *text*
> from the user. How often do you care whether someone pressed '1' on
> the top row as compared to '1' on the numeric keypad?

I don't think I've made that distinction.

A very basic model of an interactive text-based computer has input at
one end and output at the other. And a keyboard is the obvious choice
for input (a bit easier than voice and less crude than punched cards or
tape).

You can do a lot of stuff with line-based input, but how do you think
/that/ gets implemented? At some point it needs to be a character at a
time or a key at a time; the requirement is there.

Take away a keyboard, real or virtual, from a development computer (or
even one used to check your bank account or go on forums), and see how
far you get.

> Much more commonly, you simply ask for
> input from the user, and get back a line of text. The user might have
> edited that line before submitting it, and that's a feature, not a
> bug.

Yeah, 'kill dwarf with axe' and such. It works but it's limited.

Try and write a program where the keys represent the notes on a piano,
and pressing each key plays the corresponding note from speaker.

Having to press Enter after each one is going to cramp your style a bit!

And don't tell me this is advanced because I was doing stuff like this
decades ago. (Of course now I wouldn't have a clue how to make it
generate sounds.)

> When you want more flexibility than "Enter to continue or Ctrl-C to
> abort", it probably *is* time to get curses or a GUI toolkit, because
> you're doing something that's fundamentally different from "request
> text from the user".

My IDE and editor that I use every day are based on 'getchx()', an
extended version of getch(). Although it is implemented on top of Win32
which is a kind of complex GUI. (getchx returns key and shift-state
information as well as character codes.)

But the point is, it is just the one function; how it's implemented is
not relevant. It's the kind of function that it would be nice to have
/as standard/ in any language without being told that being able to deal
with key-at-a-time input is an advanced topic!

--
Bartc

Chris Angelico

unread,
Oct 25, 2016, 8:40:29 AM10/25/16
to
On Tue, Oct 25, 2016 at 11:09 PM, Marko Rauhamaa <ma...@pacujo.net> wrote:
> Chris Angelico <ros...@gmail.com>:
>
>> There's a huge difference between a loop that calls a blocking
>> function like (raw_)input and one that calls a non-blocking function
>> like kbhit(). One of them is polite to other processes; the other is
>> not.
>
> Each process can have its own PTY with a separate virtual keyboard
> interface. The main problem is that the Unix terminal interface is quite
> old and crude.

Or no PTY at all. And yes, it is crude... all it can do is allow input
of arbitrary text. You can't draw a self-portrait, you can't take a
photograph, you can't enter a mouse gesture. Terribly crude. And
perfect for anything that uses text.

>> In fact, even in a single-user single-process system, polling is a bad
>> idea - it means that nothing can go to sleep.
>
> Yes, spinning is bad. However, there are nicer ways to poll: select,
> poll, epoll...

What's the point of using select etc when you care about only one input?

>> Unless, of course, you want to reimplement the whole concept of
>> blocking calls on top of non-blocking ones, in which case... why?!?
>
> Blocking calls are evil.

Oh, that's why. Got it. So because blocking calls are fundamentally
evil, we have to... what? What's so bad about them? Remember, not
every program is a server handling myriad clients.

ChrisA

Marko Rauhamaa

unread,
Oct 25, 2016, 8:43:16 AM10/25/16
to
BartC <b...@freeuk.com>:

> Ctrl-C is not the same; that will just abort (without doing proper
> termination such as saving your data, or even just asking the user to
> confirm).

Ctrl-C is not the same, but it does let you intercept it and even ignore
it. Just handle signal.SIGINT.

> A very basic model of an interactive text-based computer has input at
> one end and output at the other. And a keyboard is the obvious choice
> for input (a bit easier than voice and less crude than punched cards
> or tape).

Text and keyboard are completely different entities. You don't find [F1]
or [Insert] or [Alt] in text nor do you distinguish between button up
and button down. Also, you can't measure the timing between the
characters in text.

Most Unix entities are right at home with text. It's the keyboard that's
problematic. The keyboard does not communicate with characters or text.
Rather it emits events with keycodes.


Marko

Marko Rauhamaa

unread,
Oct 25, 2016, 8:45:15 AM10/25/16
to
Chris Angelico <ros...@gmail.com>:
Myriads or not, we are talking about interactive (or reactive) programs.
The paradigm of choice is event-driven programming.


Marko

Chris Angelico

unread,
Oct 25, 2016, 8:49:40 AM10/25/16
to
On Tue, Oct 25, 2016 at 11:35 PM, BartC <b...@freeuk.com> wrote:
> On 25/10/2016 12:25, Chris Angelico wrote:
>>> You mean, something as sophisticated as press Enter to continue, or
>>> Escape
>>> to quit? Or Page Up and Page Down?
>>
>>
>> Enter to continue or Ctrl-C to quit. Just as easy.
>
>
> Ctrl-C is not the same; that will just abort (without doing proper
> termination such as saving your data, or even just asking the user to
> confirm).

In Python, Ctrl-C raises KeyboardInterrupt. If you want to save your
data, use standard exception handling. (And asking to confirm? Isn't
that exactly what "Press Enter to continue or Ctrl-C to abort" *is*?)

>>> But why the need to have to use someone else's massive great wheel? Both
>>> Curses and wxPython are completely over the top IMO for something so
>>> fundamental.
>>
>>
>> Fundamental? What exactly is fundamental about key-based input? Much
>> more fundamental is character-based input, where you request *text*
>> from the user. How often do you care whether someone pressed '1' on
>> the top row as compared to '1' on the numeric keypad?
>
>
> I don't think I've made that distinction.

No, but that's exactly what happens when you switch from
character-based input to key-based. You can't have both. Either you
care about text, or you care about buttons being pressed.

> A very basic model of an interactive text-based computer has input at one
> end and output at the other. And a keyboard is the obvious choice for input
> (a bit easier than voice and less crude than punched cards or tape).
>
> You can do a lot of stuff with line-based input, but how do you think /that/
> gets implemented? At some point it needs to be a character at a time or a
> key at a time; the requirement is there.
>
> Take away a keyboard, real or virtual, from a development computer (or even
> one used to check your bank account or go on forums), and see how far you
> get.

So? My programs don't care about that. They care about text. Where
that text comes from is immaterial - it could be the keyboard, it
could be the mouse (middle-click paste), it could be a file (stream
redirection), it could be anything else.

>> Much more commonly, you simply ask for
>> input from the user, and get back a line of text. The user might have
>> edited that line before submitting it, and that's a feature, not a
>> bug.
>
>
> Yeah, 'kill dwarf with axe' and such. It works but it's limited.
>
> Try and write a program where the keys represent the notes on a piano, and
> pressing each key plays the corresponding note from speaker.
>
> Having to press Enter after each one is going to cramp your style a bit!

And that's where you should be using a proper UI library - I would do
this with a GUI, but you could also use ncurses.

> And don't tell me this is advanced because I was doing stuff like this
> decades ago. (Of course now I wouldn't have a clue how to make it generate
> sounds.)

I've been doing stuff like this for decades too - and decades ago, I
was doing pretty advanced stuff. False line of argument. It sounds
like "I'm older than you, and must know better", and that wasn't much
good for Alice and the Lory either.

> But the point is, it is just the one function; how it's implemented is not
> relevant. It's the kind of function that it would be nice to have /as
> standard/ in any language without being told that being able to deal with
> key-at-a-time input is an advanced topic!

How often do you really need this functionality, and what are you
willing to give up for it? Normally, if you want that kind of thing,
you need to reach for a GUI/TUI toolkit. Yaknow, like Steve said in
the first place.

ChrisA

Chris Angelico

unread,
Oct 25, 2016, 8:56:06 AM10/25/16
to
Have you watched "Tron"? A program goes to the I/O tower to receive a
message from the User. It's an active operation on the part of the
program. The user cannot initiate it, only the program can.

Tron is extremely accurate in this way.

ChrisA

Christian Gollwitzer

unread,
Oct 25, 2016, 9:03:39 AM10/25/16
to
Am 25.10.16 um 14:45 schrieb Marko Rauhamaa:
I agree, which means (basically) GUI, which means event loop and all
that stuff, making programming more inconvenient or complicated.

That reminds me of a standard "problem" with introductory programming
texts. Many books describe the first programs along the lines of

x=input('Please enter x: ')
y=input('Please enter y: ')
print('The product is ', x*y)

Now, such programs are not useful in practice. Once you try, you will
inevitably make errors entering the data, restart that thing multiple
times and curse the author badly. "Real" programs either provide a GUI
or a command line parser which allows for the correction of errors and
entering the data in arbitrary order. Both lead to more complex programs.

Maybe some (extremely simple) option parser or GUI thingy could be
implemented into Python directly, so that the novice doesn't have to
bother with the details, in the sense of:

parameters({'x', double, 'y', double})
output('The product is ', x*y)

which becomes either a command line thingy with -x and -y options or a
GUI with input fields and an output line.

Christian

Terry Reedy

unread,
Oct 25, 2016, 9:24:21 AM10/25/16
to
On 10/24/2016 2:14 PM, jlad...@itu.edu wrote:
> After reading this rather vague thread...
>
> https://groups.google.com/forum/#!topic/comp.lang.python/FVnTe2i0UTY
>
> ... I find myself asking why Python doesn't include a standard,
> non-blocking keyboard input function. I have often wanted one
> myself. The only way that I've ever achieved this behavior is:
>
> 1) by restricting the user to pressing Ctrl-C while the program is
> running, and catching a KeyboardInterrupt; or
>
> 2) loading a heavyweight GUI like wxPython or PyQt, and using its
> event loop to intercept keyboard events.

Or load the lighter weight cross-platform tkinter GUI that comes with
Python. One can either make the GUI invisible or use at least a Text or
Entry widget instead of the OS console. The text widget comes with
numerous key and mouse bindings, including the generic "Display glyph in
response to press of graphics key".

Either way, if one wants to do a prolonged computation, one must either
put it another thread or split it into chunks of limited duration, such
50 milleseconds (1/20 second), with breaks in between that allow user
input handling.

> I gather that non-blocking keyboard input functions aren't the
> easiest thing to implement. They seem to depend on the operating
> system. Still, ease of use is a primary goal of Python, and the need
> for this feature must be common.

What is not common today is to only want asynchronous keypress handing
without the use of any GUI widget (other than the OS-supplied console).

--
Terry Jan Reedy

Random832

unread,
Oct 25, 2016, 10:36:23 AM10/25/16
to
On Tue, Oct 25, 2016, at 02:39, Steven D'Aprano wrote:
> Not really. I think that lots of people think they need it, but
> once they write a little utility, they often realise that it's not
> that useful. That's just my opinion, and I'm one of those guys who
> wrote one:
>
> http://code.activestate.com/recipes/577977-get-single-keypress/?in=user-4172944

Non-blocking (which your example here doesn't even do) isn't the same
thing as character-at-a-time. It doesn't even imply it, technically -
you could want to do other stuff and occasionally check if the user has
entered a line, though *that* is even *more* involved on Windows because
it means you can't do it with msvcrt.kbhit.

Steve D'Aprano

unread,
Oct 25, 2016, 12:06:10 PM10/25/16
to
On Tue, 25 Oct 2016 11:49 pm, Chris Angelico wrote:

> In Python, Ctrl-C raises KeyboardInterrupt. If you want to save your
> data, use standard exception handling. (And asking to confirm? Isn't
> that exactly what "Press Enter to continue or Ctrl-C to abort" *is*?)


$ Fire missiles? Press Enter to continue or Ctrl-C to abort. ^C
$ Are you sure you want to abort?
Press Enter to abort or Ctrl-C to abort the abort. ENTER
$ Did you mean to abort? Press Enter to continue aborting,
or Ctrl-C to abort aborting the abort and continue. ENTER
$ Confirm abort: Enter to abort, Ctrl-C to abort. ENTER
$ Abort aborted. Missiles fired.




--
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.

Steve D'Aprano

unread,
Oct 25, 2016, 12:22:26 PM10/25/16
to
On Wed, 26 Oct 2016 01:36 am, Random832 wrote:

> On Tue, Oct 25, 2016, at 02:39, Steven D'Aprano wrote:
>> Not really. I think that lots of people think they need it, but
>> once they write a little utility, they often realise that it's not
>> that useful. That's just my opinion, and I'm one of those guys who
>> wrote one:
>>
>>
http://code.activestate.com/recipes/577977-get-single-keypress/?in=user-4172944
>
> Non-blocking (which your example here doesn't even do) isn't the same
> thing as character-at-a-time.


Heh, I just realised exactly the same thing. I wondered how many responses
this thread would get before somebody noticed. Thanks Random.

You're right, of course. My code blocks.

So how would you do non-blocking keyboard input? How would it work? What
would be the interface?


> It doesn't even imply it, technically -
> you could want to do other stuff and occasionally check if the user has
> entered a line, though *that* is even *more* involved on Windows because
> it means you can't do it with msvcrt.kbhit.




Paul Rubin

unread,
Oct 25, 2016, 12:32:41 PM10/25/16
to
jlad...@itu.edu writes:
> ... I find myself asking why Python doesn't include a standard,
> non-blocking keyboard input function. I have often wanted one myself.

I agree this would be useful. Forth has a standard word KEY to read a
key, and I used it in a simple game that I wrote a few months ago
(you enter a key indicating which way you want to move).

> The only way that I've ever achieved this behavior is: ...

In *nix you should be able to set the tty modes with fcntl.ioctl so that
reading from stdin returns immediately when you hit a key. You should
be able to use select.select with zero timeout to see whether input is
available.

Marko Rauhamaa

unread,
Oct 25, 2016, 2:07:06 PM10/25/16
to
Steve D'Aprano <steve+...@pearwood.info>:
> So how would you do non-blocking keyboard input? How would it work?
> What would be the interface?

https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html


Marko

Chris Angelico

unread,
Oct 25, 2016, 2:23:10 PM10/25/16
to
On Wed, Oct 26, 2016 at 3:05 AM, Steve D'Aprano
<steve+...@pearwood.info> wrote:
> On Tue, 25 Oct 2016 11:49 pm, Chris Angelico wrote:
>
>> In Python, Ctrl-C raises KeyboardInterrupt. If you want to save your
>> data, use standard exception handling. (And asking to confirm? Isn't
>> that exactly what "Press Enter to continue or Ctrl-C to abort" *is*?)
>
>
> $ Fire missiles? Press Enter to continue or Ctrl-C to abort. ^C
> $ Are you sure you want to abort?
> Press Enter to abort or Ctrl-C to abort the abort. ENTER
> $ Did you mean to abort? Press Enter to continue aborting,
> or Ctrl-C to abort aborting the abort and continue. ENTER
> $ Confirm abort: Enter to abort, Ctrl-C to abort. ENTER
> $ Abort aborted. Missiles fired.

http://www.gotterdammerung.org/humor/boh13.html

(Sadly, the official bofh.ntk.net is down, or I'd link to it there.)

ChrisA

Nobody

unread,
Oct 25, 2016, 3:57:06 PM10/25/16
to
On Mon, 24 Oct 2016 11:14:05 -0700, jladasky wrote:

> I gather that non-blocking keyboard input functions aren't the easiest
> thing to implement. They seem to depend on the operating system.

Indeed. It's somewhat harder to implement one on an OS which doesn't take
it for granted that the system actually *has* a keyboard (i.e. Unix).

If you're willing to compromise and accept the use of a terminal rather
than a keyboard, the next question is whether to use the process'
controlling terminal, or the terminal associated with stdin (if both
exist, they're probably the same terminal, but aren't required to be).

Other complications include the fact that, if the process isn't part of
the terminal's foreground process group, attempting to read from the
terminal (even a non-blocking read) will typically suspend the process
(unless you ignore SIGTTIN). And also the fact that the terminal itself
may be line buffered, so the computer has no idea of what's being typed on
it until Return/Enter (or Send, etc) is pressed.

Aside from that, receiving key presses as they are entered means disabling
canonical mode in the tty driver (which buffers input until Return or
Ctrl-D are pressed, so that you can edit the input line with Backspace or
Ctrl-U). That affects all processes using the terminal.

If the current process is in the foreground process group, then processes
in other groups probably won't be reading from the terminal ... at least
until you suspend the forground process group with Ctrl-Z. So you need to
install signal handlers for SIGTSTP and SIGCONT to restore the terminal
settings when the process is suspended. But what should you do about any
existing handlers for those signals?

All things considered, requiring the user to use one of the keys that
generates a signal might be simpler. Or at least not using Esc, which is
about the worst possible choice, given that its normal function is
as a prefix for, well, just about every control sequence (i.e. what is
sent when you press a key which doesn't correspond to a printable
character).

tl;dr: Unix is not MS-DOS.

Marko Rauhamaa

unread,
Oct 25, 2016, 5:25:10 PM10/25/16
to
Nobody <nob...@nowhere.invalid>:

> On Mon, 24 Oct 2016 11:14:05 -0700, jladasky wrote:
>> I gather that non-blocking keyboard input functions aren't the
>> easiest thing to implement. They seem to depend on the operating
>> system.
>
> Indeed. It's somewhat harder to implement one on an OS which doesn't
> take it for granted that the system actually *has* a keyboard (i.e.
> Unix).

I don't think that's very relevant.

> [...]
> controlling terminal, or the terminal associated with stdin [...]
>
> Other complications include the fact that, if the process isn't part
> of the terminal's foreground process group, attempting to read from
> the terminal (even a non-blocking read) will typically suspend the
> process (unless you ignore SIGTTIN). And also the fact that the
> terminal itself may be line buffered, so the computer has no idea of
> what's being typed on it until Return/Enter (or Send, etc) is pressed.

Arcane schemes that reflect ancient realities. Unix came about when
wasting CPU cycles processing terminal commands was considered
extravagant -- CPU cycles were charged to the customers. Nowadays, of
course, the CPU processes all keyboard events and commits even more
atrocious things like micromanages individual pixels on the screen and
encrypts and decrypts all external communication.

> [...]
>
> tl;dr: Unix is not MS-DOS.

Thankfully, you don't need to run your program from a terminal. You can
interpret keyboard events any way you want if your program is an X11 or
Wayland client, and forget all about TTYs, baud rates, parity bits,
hangups etc.

In fact, that's what emacs does, for example. It can operate in a
terminal (and I take advantage of that every day) but I'm typing this in
emacs running under X11.


Marko

Chris Angelico

unread,
Oct 25, 2016, 5:57:54 PM10/25/16
to
On Wed, Oct 26, 2016 at 8:24 AM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>
> Thankfully, you don't need to run your program from a terminal. You can
> interpret keyboard events any way you want if your program is an X11 or
> Wayland client, and forget all about TTYs, baud rates, parity bits,
> hangups etc.

That still doesn't answer the fundamental question:

Are you looking for KEYBOARD input or TEXT input?

Until you figure that out, nothing matters. Personally, I'd much
rather work with text than with actual keys; in the uncommon case
where I want a keystroke to trigger an action, I'm always working in a
GUI already, and I can create a menu item with an accelerator. A
visible one.

Just because you *can* poll the keyboard for events, don't think that
you *should*.

ChrisA

BartC

unread,
Oct 25, 2016, 6:30:21 PM10/25/16
to
On 25/10/2016 22:57, Chris Angelico wrote:
> On Wed, Oct 26, 2016 at 8:24 AM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>>
>> Thankfully, you don't need to run your program from a terminal. You can
>> interpret keyboard events any way you want if your program is an X11 or
>> Wayland client, and forget all about TTYs, baud rates, parity bits,
>> hangups etc.
>
> That still doesn't answer the fundamental question:
>
> Are you looking for KEYBOARD input or TEXT input?

Does it matter that much?

Because even if you opt for TEXT, the input (when interactive which is
what we're talking about) is usually chopped up into LINE events. What's
the difference if we want to concentrate on CHAR or KEY events instead?

I've used enough line-buffered editors on teletypes and serial VDUs to
remember them as horrible to use. Was the input considered TEXT or
KEYBOARD? I can't remember but it wasn't really important.

And no one has the answered the question of how Curses or a GUI solves
the problem of getting char or key events. Same machine, same OS, same
keyboard, but one piece of software has apparently discovered the secret
which is then denied to other software.

> Until you figure that out, nothing matters. Personally, I'd much
> rather work with text than with actual keys; in the uncommon case
> where I want a keystroke to trigger an action, I'm always working in a
> GUI already, and I can create a menu item with an accelerator. A
> visible one.

Some people want to work at low level, without needing to drag in a GUI,
and want to do something as simple as finding out if a button has been
pressed on a standard peripheral that nearly every computer has. It
can't be that hard!

> Just because you *can* poll the keyboard for events, don't think that
> you *should*.

With my rare forays into GUI, that's exactly what I end up doing: in a
loop waiting for events.

--
Bartc

Chris Angelico

unread,
Oct 25, 2016, 6:59:12 PM10/25/16
to
On Wed, Oct 26, 2016 at 9:30 AM, BartC <b...@freeuk.com> wrote:
>> That still doesn't answer the fundamental question:
>>
>> Are you looking for KEYBOARD input or TEXT input?
>
>
> Does it matter that much?
>
> Because even if you opt for TEXT, the input (when interactive which is what
> we're talking about) is usually chopped up into LINE events. What's the
> difference if we want to concentrate on CHAR or KEY events instead?

Yes, it does. Text does not include "Home" or "Delete", but it does
include all manner of symbols that aren't on everyone's keyboards. It
makes a huge difference.

Of course, you might want to stick your head in the sand and pretend
that every character has a button on your keyboard.

ChrisA

BartC

unread,
Oct 25, 2016, 7:45:52 PM10/25/16
to
On 25/10/2016 23:58, Chris Angelico wrote:
> On Wed, Oct 26, 2016 at 9:30 AM, BartC <b...@freeuk.com> wrote:
>>> That still doesn't answer the fundamental question:
>>>
>>> Are you looking for KEYBOARD input or TEXT input?
>>
>>
>> Does it matter that much?
>>
>> Because even if you opt for TEXT, the input (when interactive which is what
>> we're talking about) is usually chopped up into LINE events. What's the
>> difference if we want to concentrate on CHAR or KEY events instead?
>
> Yes, it does. Text does not include "Home" or "Delete", but it does
> include all manner of symbols that aren't on everyone's keyboards. It
> makes a huge difference.

Actually TXT files can include codes such as Carriage Return, Backspace
and Tab.

> Of course, you might want to stick your head in the sand and pretend
> that every character has a button on your keyboard.

I'm not sure of the relevance of that. There isn't a 1:1 correspondence
between key and character code. So 'a' and 'A' might both be entered by
pressing the key marked 'A'. With, possibly, some underlying translation
so that the 'A' key can vary locations by locale. That isn't new.

It doesn't seem to me that anyone is denying that key-at-a-time access
is useful in a wide range of programs. They just seem to be unwilling to
let it be it available in a simple, standard form. We are expected to
download wxPython first.

--
Bartc

Travis Griggs

unread,
Oct 25, 2016, 7:50:53 PM10/25/16
to

> On Oct 25, 2016, at 5:55 AM, Chris Angelico <ros...@gmail.com> wrote:
> Have you watched "Tron"? A program goes to the I/O tower to receive a
> message from the User. It's an active operation on the part of the
> program. The user cannot initiate it, only the program can.
>
> Tron is extremely accurate in this way.

Thanks for this ChrisA. Rest of this thread has been meh for me, but this one post, definitely won my MostValueablePost for the thread. :)

Still chuckling.

Steve D'Aprano

unread,
Oct 25, 2016, 9:02:33 PM10/25/16
to
On Tue, 25 Oct 2016 09:02 pm, BartC wrote:

>> raw_input('Press the Enter key to continue... ')
>
> Which doesn't work on Python 3. So even here, making it easy by using
> line-input, it's not so straightforward.

Really, Bart? You're stymied by the change of raw_input() to input() in
Python 3? A programmer of your many years experience and skill can't work
out how to conditionally change "raw_input" to "input" according to the
version of the interpreter running. I don't think so.


>> If you are doing something more complex, waiting on different keys to do
>> different things,
>
> You mean, something as sophisticated as press Enter to continue, or
> Escape to quit? Or Page Up and Page Down?

This discussion is a red herring, because the OP is talking about
non-blocking input. So "Press enter to continue" is not a good model for
what he had in mind.

But regardless, yes, I'd consider using an existing text UI at this point,
rather than try re-inventing the wheel. Unless I *like* re-inventing the
wheel, or that's what I'm being paid for. If I've got two keys to choose
between, I'll probably have more soon:

Page Up, Page Down, Line Up, Line Down, Backwards, Forwards, Refresh, Quit,
Load File, Reload File ...

Somebody once said, there's really only three numbers you need care about.
Zero, one and infinity. Zero is easy to handle -- you don't do anything.
One is easy, because there's only one thing to do. But once you have two
things, you might as well be prepared to handle an indefinitely large
number of things, because you're surely going to need to.

YMMV.



>> then you probably should use an existing text UI like Curses,
>> or a GUI like wxPython etc, rather than trying to reinvent the wheel
>> badly.
>
> But why the need to have to use someone else's massive great wheel? Both
> Curses and wxPython are completely over the top IMO for something so
> fundamental.

*shrug* Then find a more lightweight solution. Tkinter? Something even
lighter?

Maybe there is no such lightweight solution? Then that tells you that nobody
else needed this enough to build a solution. Perhaps you're the first!
Congratulations!

Or perhaps you're looking at the question the wrong way. How many thousands
of man-hours, and deaths, came about because people thought that the only
way to fly was by flapping wings like a bird? Maybe there are other ways to
fly... maybe there are other ways to get a good text UI other than
collecting raw keyboard events.

I don't know. I've never needed this enough to care to investigate. Like I
said, it *seems* like the sort of obvious functionality every programmer
should need all the time, but in 15 years I've never, not once, actually
needs a non-blocking way to check for a keyboard event in a situation where
I wasn't using something like curses or a GUI framework.

YMMV.


[...]
> This gives you the ability to do (2) above. From that, you could do (1)
> (echoing) and go on to build full line-orientated input. But you had
> complete control.
>
> So, why has it all become so difficult?

Build line oriented input? Why would I do that, when the OS does it?

Okay, sure, if you're programming for some sort of primitive system with no
OS or such a feeble one that it didn't even offer line-oriented text I/O,
then needs must, and you have to do what the OS doesn't provide. But that
sort of low-level I/O is precisely what operating systems are for.

Terry Reedy

unread,
Oct 25, 2016, 10:26:26 PM10/25/16
to
On 10/25/2016 7:45 PM, BartC wrote:
> On 25/10/2016 23:58, Chris Angelico wrote:

>> Yes, it does. Text does not include "Home" or "Delete", but it does
>> include all manner of symbols that aren't on everyone's keyboards. It
>> makes a huge difference.
>
> Actually TXT files can include codes such as Carriage Return, Backspace
> and Tab.

These are called 'control *characters*' because, like characters, they
are represented as encoded bytes or, now, as unicode codepoints. 'Home'
is not a control character. (I don't know if there is a unicode
codepoint for it.)

>> Of course, you might want to stick your head in the sand and pretend
>> that every character has a button on your keyboard.
>
> I'm not sure of the relevance of that. There isn't a 1:1 correspondence
> between key and character code. So 'a' and 'A' might both be entered by
> pressing the key marked 'A'. With, possibly, some underlying translation
> so that the 'A' key can vary locations by locale. That isn't new.

The translation used to be done by a physically separate terminal and
communication between computer and and terminal was via encoded bytes.
A program could not access keystrokes because the computer never saw
them. Python normally runs in a terminal or console that translates
keycodes to encoded bytes

> It doesn't seem to me that anyone is denying that key-at-a-time access
> is useful in a wide range of programs. They just seem to be unwilling to
> let it be it available in a simple, standard form.

The simple, standard form for Python, as well as for tcl, perl, and
ruby, is as tk events. Python accesses then via tkinter. Other
languages have their own version of the API.

> We are expected to download wxPython first.

Since this is not true, why do you keep repeating it?

--
Terry Jan Reedy

Michael Torrie

unread,
Oct 25, 2016, 10:37:49 PM10/25/16
to
On 10/25/2016 10:22 AM, Steve D'Aprano wrote:
> So how would you do non-blocking keyboard input? How would it work? What
> would be the interface?

Curses must allow you to do this because I've seen text-mode games made
in curses and you could do things with arrow keys, etc, all while ascii
animation was going on. Now it could be that curses forces you into an
event-driven paradigm. Not sure about that. But even if it did, your
event loop could run a callback that would deposit keystrokes (if any)
into another buffer of some kind that your non-event-driven thread could
peak into.

Marko Rauhamaa

unread,
Oct 26, 2016, 12:44:47 AM10/26/16
to
BartC <b...@freeuk.com>:
> And no one has the answered the question of how Curses or a GUI solves
> the problem of getting char or key events. Same machine, same OS, same
> keyboard, but one piece of software has apparently discovered the
> secret which is then denied to other software.

Curses, emacs, vi, bash, CPython, nethack etc "solve the problem" by
setting the terminal mode. You can, too:

https://docs.python.org/3/library/termios.html
https://docs.python.org/3/library/tty.html

However, that only gives you access to the interpreted characters. For
example, you can't see when a [Shift] key has been pressed.

> Some people want to work at low level, without needing to drag in a GUI,
> and want to do something as simple as finding out if a button has been
> pressed on a standard peripheral that nearly every computer has. It
> can't be that hard!

I don't consider that to be very low level. If you want to get to the
low level, open

/dev/input/by-id/*-event-kbd

See:

http://stackoverflow.com/questions/3662368/dev-input-keyboard-format


Marko

BartC

unread,
Oct 26, 2016, 7:19:08 AM10/26/16
to
On 26/10/2016 02:02, Steve D'Aprano wrote:
> On Tue, 25 Oct 2016 09:02 pm, BartC wrote:
>
>>> raw_input('Press the Enter key to continue... ')
>>
>> Which doesn't work on Python 3. So even here, making it easy by using
>> line-input, it's not so straightforward.
>
> Really, Bart? You're stymied by the change of raw_input() to input() in
> Python 3? A programmer of your many years experience and skill can't work
> out how to conditionally change "raw_input" to "input" according to the
> version of the interpreter running. I don't think so.

I could probably figure it out. But how about a beginner?

(When I post Python code I try and make sure it works on both, or
specify which version.)

>> But why the need to have to use someone else's massive great wheel? Both
>> Curses and wxPython are completely over the top IMO for something so
>> fundamental.
>
> *shrug* Then find a more lightweight solution. Tkinter? Something even
> lighter?

Can tkinter do it without creating a distracting pop-up window at the
same time? If not then that's too intrusive.

Curses? If I try 'import curses' (on Windows), I get 'No module named
'_curses'. Same with ncurses or Curses. Now instead of getting on with
it I have to go chasing some add-on. And if I want to share a bit of
code with someone else, then /they/ have to do the same!

My point is that this simple stuff just be included in a language.

> Maybe there is no such lightweight solution? Then that tells you that nobody
> else needed this enough to build a solution.

I find this a lot with stuff that originates on Unix or Linux.

(Do you know when I create executables that run on Linux, I have to try
and cram all the support files within the executable itself - because it
appears to be impossible to discover the path the executable was started
from. With a view to using the same or adjoining path for associated
files. When I ask about this, Oh it's never been needed!

Same with basic keyboard stuff that any microcomputer from the 80s could
do in an instant.)

> I don't know. I've never needed this enough to care to investigate. Like I
> said, it *seems* like the sort of obvious functionality every programmer
> should need all the time, but in 15 years I've never, not once, actually
> needs a non-blocking way to check for a keyboard event in a situation where
> I wasn't using something like curses or a GUI framework.

By non-blocking you mean checking if a key has been pressed rather than
waiting for it to be pressed? I use the latter ALL THE TIME when
debugging. The former less often, because if I wanted to use it to abort
huge amounts of output, I just abort the program (with Ctrl Break).

Nevertheless, it is still used sometimes, and it's there when I need it
(NOT Python):

repeat
print "A"
until testkey()

>> So, why has it all become so difficult?
>
> Build line oriented input? Why would I do that, when the OS does it?

Sometimes you want your own line-input functions because they need to be
customised to do special things. Assign special meanings to certain key
events for example.

You make it sound completely crazy like building your own OS. But I've
done this dozens of times (and yes including when there /was/ no OS), it
really isn't a big deal. Except when a language strives to make it so.

> I don't know. I've never needed this enough to care to investigate.

Try this little task. In the late 70s I was fascinated by the ability of
a teletype to do this: it would ask a Yes/No question, perhaps:

.CONFIRM (YES/NO):

But then, instead of typing YES<return> or NO<return>, if either Y or N
was pressed, it would auto-complete it, printing 'ES' or 'O' and doing a
Return for you ("." is the prompt; you have to imagine the clatter):

.CONFIRM (YES/NO): YES
.

How hard is it to do this nearly 40 years On a machines a million times
more powerful? And in Python (although I'd imagine any difficulties it
has originate outside the language and probably affect others).


Bartc

BartC

unread,
Oct 26, 2016, 7:34:40 AM10/26/16
to
On 26/10/2016 05:44, Marko Rauhamaa wrote:
> BartC <b...@freeuk.com>:

>> Some people want to work at low level, without needing to drag in a GUI,
>> and want to do something as simple as finding out if a button has been
>> pressed on a standard peripheral that nearly every computer has. It
>> can't be that hard!
>
> I don't consider that to be very low level.

I think working in text mode (character-based display) and a key at a
time is enough to be called low-level.

Lower than that would be directly working with the hardware. But it gets
more specific as keyboards work in different ways. That's not so useful
or interesting.

(I've implemented 'keyboards' both on-screen, and on the surface of
digitising tablets (also with a hacked Casio calculator pcb when I
couldn't afford a real one). With all of those I was mainly interested
in key events, not the details.)

If you want to get to the
> low level, open
>
> /dev/input/by-id/*-event-kbd
>
> See:
>
> http://stackoverflow.com/questions/3662368/dev-input-keyboard-format

That's not what I'd call low-level. It's more building a mountain of
complexity around something that ought to be straightforward. Apparently
when you need to dig very deeply to get through to the fundamentals,
that's now called 'low-level'!

--
bartc

Marko Rauhamaa

unread,
Oct 26, 2016, 8:33:26 AM10/26/16
to
BartC <b...@freeuk.com>:

> On 26/10/2016 05:44, Marko Rauhamaa wrote:
> (I've implemented 'keyboards' both on-screen, and on the surface of
> digitising tablets (also with a hacked Casio calculator pcb when I
> couldn't afford a real one). With all of those I was mainly interested
> in key events, not the details.)

Say you want to implement a simple, character-based shooting game where
the two guns are operated by the [Shift] keys. Unfortunately, the Unix
terminal API doesn't make that possible. You need to get the keyboard
events from some other API. In practice, your only choice is X11/Wayland
(on Linux).

> It's more building a mountain of complexity around something that
> ought to be straightforward.

Maybe there should be some way to get the raw events from the PTY.
However, next you'd start wanting the mouse events and pixel-level color
controls. It starts to look like a GUI application.

But what would be wrong in a GUI PTY API? No windowing, just a regular
character display where you could draw pictures and interpret the inputs
directly à la Apple II or Commodore 64.

It would make teaching programming much more fun, too.


Marko

BartC

unread,
Oct 26, 2016, 11:00:26 AM10/26/16
to
On 26/10/2016 13:33, Marko Rauhamaa wrote:
> BartC <b...@freeuk.com>:
>
>> On 26/10/2016 05:44, Marko Rauhamaa wrote:
>> (I've implemented 'keyboards' both on-screen, and on the surface of
>> digitising tablets (also with a hacked Casio calculator pcb when I
>> couldn't afford a real one). With all of those I was mainly interested
>> in key events, not the details.)
>
> Say you want to implement a simple, character-based shooting game where
> the two guns are operated by the [Shift] keys. Unfortunately, the Unix
> terminal API doesn't make that possible. You need to get the keyboard
> events from some other API. In practice, your only choice is X11/Wayland
> (on Linux).

That sort of thing is possible to build by directly calling OS-specific
functions in a similar manner to Steven D'Aprano's way of implementing
getch().

But it's something everyone would have to code themselves.

(I just tried it using my 'getchx' function where it ought to have
worked. Unfortunately MS' interface to key events doesn't seem to
distinguish between left and right shift keys. But it was doable with
left/right ctrl keys.

That's a blocking function it it means having to wait for input. But a
version that just tests for status shouldn't be hard.)

--
Bartc

Terry Reedy

unread,
Oct 26, 2016, 7:31:09 PM10/26/16
to
On 10/26/2016 7:18 AM, BartC wrote:

> Can tkinter do it without creating a distracting pop-up window at the
> same time?

Yes. I already showed how on this thread. Of course, for some text
appications, one would be better off with a Text widget than with the
system-specific console.

Bart, you appear to have been fortunate enough to be spoiled by learning
programming on microcomputers, where the terminal and computer are
combined into one unit, so that the computer, and potentially the
programmer, have access to user input actions. However, Python was not
developed on, and in not limited to use on, such machines. Today,
ethernet-connected *nix servers have no keyboard, mouse, or even a
directly connected terminal.

When Python was developed, standard C did not have keyboard and mouse
functions. (I don't know about the most recent standards.) Keyboard
functions on microcomputer C ports were non-standard OS-specific
extensions. On Unix, X windows was and is optional.

Over 20 years ago, tk was written in tcl and C to give tcl programmers
access to X Windows graphics terminals, including user input actions.
It has since been ported to MS Windows and Apple OSX and adopted by
other languages, including Python, to give the same access.

--
Terry Jan Reedy

Terry Reedy

unread,
Oct 26, 2016, 8:34:20 PM10/26/16
to
On 10/26/2016 8:33 AM, Marko Rauhamaa wrote:
> BartC <b...@freeuk.com>:

> Say you want to implement a simple, character-based shooting game where
> the two guns are operated by the [Shift] keys. Unfortunately, the Unix
> terminal API doesn't make that possible. You need to get the keyboard
> events from some other API. In practice, your only choice is X11/Wayland
> (on Linux).

Or tk(inter), which uses X11 on *nix and other stuff on OSX and Windows.
I verified that it gives access to the Shift keys as keys in
themselves, rather than just as modifiers.

import tkinter as tk
root = tk.Tk()
def lshift(event): print('shift-l')
def rshift(event): print('shift-r')
root.bind('<Key-Shift_L>', lshift)
root.bind('<Key-Shift_R>', rshift)
root.mainloop()

does what I hoped, with autorepeat when the key was held down.

>> It's more building a mountain of complexity around something that
>> ought to be straightforward.
>
> Maybe there should be some way to get the raw events from the PTY.

PTY? Must be Linux-specific. Most beginners are not on Linux.

> However, next you'd start wanting the mouse events and pixel-level color
> controls. It starts to look like a GUI application.
>
> But what would be wrong in a GUI PTY API? No windowing,

'No windowing'? Python normally runs in a text widget in a window,
programmed to emulate a dumb terminal. The request for non-blocking
access to user actions is a request for something smarter.

> just a regular
> character display where you could draw pictures and interpret the inputs
> directly à la Apple II or Commodore 64.

I never touched an Apple II and only briefly a Commodore 64, so either
never knew or have forgotten the Basic commands they had. But it should
be possible to emulate at least the text screen of either with tkinter.
(Graphics modes with pixel peek and poke might also be possible with a
Canvas, but I won't claim that without knowing more.) It should then be
possible to translate old games into Python.

Maybe something like this has been done?

> It would make teaching programming much more fun, too.

The logo-in-Python turtle module is already used for this.

What would be doable and possibly useful would be a textscreen module
with a Screen class that does as much boilerplate for people as
possible. For my proof-of-concept above, something like

from textscreen import Screen
def lshift(event): print('shift-l')
def rshift(event): print('shift-r')
Screen().go

should be enough. The go method should import tkinter, create root, add
a Text, scan globals() for functions with key names (and names of mouse
actions), bind any that are found, and start mainloop.

This sort of thing would be even nicer if and when tcl/tk gains support
for the full unicode character set so that all the non-BMP emoji are
potentially available. (A font supporting such would also be needed.)

--
Terry Jan Reedy


BartC

unread,
Oct 26, 2016, 9:13:07 PM10/26/16
to
On 27/10/2016 00:30, Terry Reedy wrote:
> On 10/26/2016 7:18 AM, BartC wrote:
>
>> Can tkinter do it without creating a distracting pop-up window at the
>> same time?
>
> Yes. I already showed how on this thread. Of course, for some text
> appications, one would be better off with a Text widget than with the
> system-specific console.
>
> Bart, you appear to have been fortunate enough to be spoiled by learning
> programming on microcomputers, where the terminal and computer are
> combined into one unit, so that the computer, and potentially the
> programmer, have access to user input actions.

Actually, I first used machines such as pdp10 and pdp11. Those mostly
used serial terminals, a mystery to me, and they still are. It seems
Unix is keen to propagate the mystery.

However, Python was not
> developed on, and in not limited to use on, such machines. Today,
> ethernet-connected *nix servers have no keyboard, mouse, or even a
> directly connected terminal.

So how does your tkinter example work in such a server? As I don't
understand the argument that a language shouldn't have a basic keyboard
API because some computers it could run on might not have a keyboards.

Anyway vast numbers of /consumer/ machines /do/ have displays and
keyboards. Look at any computer in an office: it has a display and
keyboard. Look at any laptop: display and keyboard. Even a tablet can
have an on-screen keyboard or have a real one plugged in.

> Over 20 years ago, tk was written in tcl and C to give tcl programmers
> access to X Windows graphics terminals, including user input actions. It
> has since been ported to MS Windows and Apple OSX and adopted by other
> languages, including Python, to give the same access.

OK. I was writing graphics applications before a lot of those things
existed. They needed to use a display and they needed user input, and I
had to make it work. I couldn't ask my customers to wait a decade or so
until someone invented an API before they could fully use their keyboards!

(I've looked at X Windows; bloody hell, it makes Win32/GDI look like
child's play. It's quite frustrating see things that used to be so
simple to do become next to impossible.)

--
Bartc

Terry Reedy

unread,
Oct 26, 2016, 10:16:04 PM10/26/16
to
On 10/26/2016 11:00 AM, BartC wrote:
> On 26/10/2016 13:33, Marko Rauhamaa wrote:

>> Say you want to implement a simple, character-based shooting game where
>> the two guns are operated by the [Shift] keys. Unfortunately, the Unix
>> terminal API doesn't make that possible. You need to get the keyboard
>> events from some other API. In practice, your only choice is X11/Wayland
>> (on Linux).

This is trivial with tkinter and practical if one uses a tk Text. See
below for the problem with using tkinter and console.

> That sort of thing is possible to build by directly calling OS-specific
> functions in a similar manner to Steven D'Aprano's way of implementing
> getch().
>
> But it's something everyone would have to code themselves.
>
> (I just tried it using my 'getchx' function where it ought to have
> worked. Unfortunately MS' interface to key events doesn't seem to
> distinguish between left and right shift keys. But it was doable with
> left/right ctrl keys.
>
> That's a blocking function it it means having to wait for input. But a
> version that just tests for status shouldn't be hard.)

In my answer to Marko, I posted code which worked as far as I tested it.
Here I add a line to make the tk window invisible. I also replace
rshift with a function that gets input from the user.

import tkinter as tk
root = tk.Tk()
root.withdraw() # make tk window invisible
def lshift(event): print('shift-l')
def rshift(event):
s = input('type something: ')
print('received', s)
root.bind('<Key-Shift_L>', lshift)
root.bind('<Key-Shift_R>', rshift)
root.mainloop()

For input, the problem is input focus. When the tk window is created,
the OS gives it input focus. Leaving itself invisible does not negate
that. But to respond to input in a different window, the user must, as
least on Windows, click on the input window. I do not know of any way
for tkinter to give focus back to a parent window that is either not a
tk window or is not in the same process.

After input is received, or indeed after focus is moved by clicking on
any other window, there is the problem of moving focus back to the tk
window. If it is invisible, it cannot be clicked on. And without a
binding to stop mainloop when the focus leaves, there is no way to stop
it without killing the console, or with IDLE, restarting Shell.

I conclude that if one uses tkinter to captures and process some
keyboard events, one should do so for all. Python's input should be
replaced by a tkinter simulation. I can think of a couple of ways this
might be implemented.

--
Terry Jan Reedy

eryk sun

unread,
Oct 26, 2016, 11:46:49 PM10/26/16
to
On Wed, Oct 26, 2016 at 11:39 AM, Dennis Lee Bieber
<wlf...@ix.netcom.com> wrote:
> Curses .... tends to not be available on Windows as M$ hasn't implemented a
> compatible console driver.

The PDCurses library supports the Windows console. Christoph Gohlke
distributes a curses extension module based on it:

http://www.lfd.uci.edu/~gohlke/pythonlibs/#curses

Paul Rubin

unread,
Oct 27, 2016, 12:08:54 AM10/27/16
to
Terry Reedy <tjr...@udel.edu> writes:
> Today, ethernet-connected *nix servers have no
> keyboard, mouse, or even a directly connected terminal.

Usually you ssh into them and connect to a pty which supports the same
ioctls that a real terminal would. I use screen editors over ssh all
the time, not to mention filters like "more" where you press the space
bar to scroll to the next page. It's sad that there's no easy way to do
that in Python.

Grant Edwards

unread,
Oct 27, 2016, 12:27:35 AM10/27/16
to
On 2016-10-27, Paul Rubin <no.e...@nospam.invalid> wrote:
> Terry Reedy <tjr...@udel.edu> writes:
>
>> Today, ethernet-connected *nix servers have no keyboard, mouse, or
>> even a directly connected terminal.
>
> Usually you ssh into them and connect to a pty which supports the
> same ioctls that a real terminal would.

On all the Unixes/Linuxs I know of, a pty supports a _subset_ of those
that a real tty supports. The fact that some of them are missing has
annoyed me for decades because it prevents you from implementing a
serial port in user-space[1]. I've offered a few times to extend the
Linux pty driver to support the same set of ioctl calls that a tty
does (so that it could be used in place of a tty generally), but I've
never gotten any response.

> I use screen editors over ssh all the time, not to mention filters
> like "more" where you press the space bar to scroll to the next
> page. It's sad that there's no easy way to do that in Python.

Yep, among the ioctl calls that ptys do support are those that allow
you to do raw and non-blocking input.

[1] The fact that Windows allows you to implement a serial port in
userspace and Linux doesn't just adds insult to injury.

--
Grant


Marko Rauhamaa

unread,
Oct 27, 2016, 1:49:43 AM10/27/16
to
Terry Reedy <tjr...@udel.edu>:

> On 10/26/2016 8:33 AM, Marko Rauhamaa wrote:
>> Maybe there should be some way to get the raw events from the PTY.
>
> PTY? Must be Linux-specific. Most beginners are not on Linux.

A PTY is an emulated console (<URL:
https://en.wikipedia.org/wiki/Pseudoterminal>). I don't know Windows but
I would guess cmd.exe does something similar there.

Also, I have no statistics on most beginning programmers operating
systems.

>> But what would be wrong in a GUI PTY API? No windowing,
>
> 'No windowing'? Python normally runs in a text widget in a window,
> programmed to emulate a dumb terminal.

Must be Windows-specific.

> I never touched an Apple II and only briefly a Commodore 64, so either
> never knew or have forgotten the Basic commands they had. But it should
> be possible to emulate at least the text screen of either with
> tkinter.

Everything is possible for an individual application (like Python). The
TTY/PTY interface enhancement I was entertaining would be a new API
provided by the OS to all programs.


Marko

Marko Rauhamaa

unread,
Oct 27, 2016, 1:56:28 AM10/27/16
to
Grant Edwards <grant.b...@gmail.com>:
> I've offered a few times to extend the Linux pty driver to support the
> same set of ioctl calls that a tty does (so that it could be used in
> place of a tty generally), but I've never gotten any response.

Ah, Linux kernel politics are Byzantine. It's virtually impossible to
get a hearing at the linux-kernel main mailing list. Did you try one of
the targeted mailing lists on <URL:
http://vger.kernel.org/vger-lists.html>?


Marko

Steven D'Aprano

unread,
Oct 27, 2016, 2:52:11 AM10/27/16
to
On Thursday 27 October 2016 12:12, BartC wrote:

> I don't
> understand the argument that a language shouldn't have a basic keyboard
> API because some computers it could run on might not have a keyboards.

That's not the argument. The argument is that Python has a basic keyboard API:
raw_input (in Python 2) or input (in 3).

This supports 97% of keyboard-based interaction, namely blocking line-based
text input. Ctrl-C (KeyboardInterrupt) can be co-opted to support maybe another
one or two percent.

The question is, what are the use-cases for the sorts of key APIs you are
asking for? Who needs them? Why should it be a language feature?

Those are not rhetoricial questions.

Python falls neatly into the same niche of languages as (for example) Ruby,
Javascript, Lua, Swift, Tcl, and (not quite as well) bash, Java, Julia. Which
of these languages offer non-blocking keyboard input as a standard part of the
language?


Python has no "peek" and "poke" memory access commands either. It's not 1972
and programming has moved on. The utility of something like this feature is
very low, the amount of effort needed for a cross-platform solution is very
high.



--
Steven
git gets easier once you get the basic idea that branches are homeomorphic
endofunctors mapping submanifolds of a Hilbert space.

Terry Reedy

unread,
Oct 27, 2016, 3:07:17 AM10/27/16
to
On 10/27/2016 1:49 AM, Marko Rauhamaa wrote:
> Terry Reedy <tjr...@udel.edu>:
>
>> On 10/26/2016 8:33 AM, Marko Rauhamaa wrote:
>>> Maybe there should be some way to get the raw events from the PTY.
>>
>> PTY? Must be Linux-specific. Most beginners are not on Linux.
>
> A PTY is an emulated console (<URL:
> https://en.wikipedia.org/wiki/Pseudoterminal>). I don't know Windows but
> I would guess cmd.exe does something similar there.
>
> Also, I have no statistics on most beginning programmers operating
> systems.
>
>>> But what would be wrong in a GUI PTY API? No windowing,
>>
>> 'No windowing'? Python normally runs in a text widget in a window,
>> programmed to emulate a dumb terminal.
>
> Must be Windows-specific.

Not as I meant the above.

When I used unix in the 1980s, the full screen ran csh until one started
another full screen application. MSDOS was the same. Every contemporary
photo of modern Linux or Mac I have seen has a desktop with windows just
like Windows. Do people on Linux still commonly use full-screen, no
window text editors like the one I had? On Windows, there are full
screen games, but I have never seen a full-screen, no-window text
application.

Since modern screen are pixel graphics screens, rather than character
screens, there must be a widget, whether standard with the OS or custom
to the console, that emulates the old fixed-pitch character screens. At
least on Windows, C Programs that run with the console still get
characters entered by users and send characters to be displayed.

--
Terry Jan Reedy

D'Arcy Cain

unread,
Oct 27, 2016, 3:56:37 AM10/27/16
to
On 2016-10-27 03:05 AM, Terry Reedy wrote:
> When I used unix in the 1980s, the full screen ran csh until one started
> another full screen application. MSDOS was the same. Every contemporary
> photo of modern Linux or Mac I have seen has a desktop with windows just
> like Windows. Do people on Linux still commonly use full-screen, no
> window text editors like the one I had? On Windows, there are full
> screen games, but I have never seen a full-screen, no-window text
> application.

You must lead a sheltered life then.

> Since modern screen are pixel graphics screens, rather than character

Not always. I have many Unix systems that don't run X. A GUI is not
essential to running a useful Unix server.

You may be correct that Linux systems tend to run GUIs but even then it
isn't mandatory.

--
D'Arcy J.M. Cain
System Administrator, Vex.Net
http://www.Vex.Net/ IM:da...@Vex.Net
VoIP: sip:da...@Vex.Net

Terry Reedy

unread,
Oct 27, 2016, 6:08:06 AM10/27/16
to
On 10/26/2016 9:12 PM, BartC wrote:
> On 27/10/2016 00:30, Terry Reedy wrote:

>> Bart, you appear to have been fortunate enough to be spoiled by learning
>> programming on microcomputers, where the terminal and computer are
>> combined into one unit, so that the computer, and potentially the
>> programmer, have access to user input actions.
>
> Actually, I first used machines such as pdp10 and pdp11. Those mostly
> used serial terminals, a mystery to me, and they still are. It seems
> Unix is keen to propagate the mystery.

OK, you got spoiled later ;-). I share your frustration a bit.

>> However, Python was not
>> developed on, and in not limited to use on, such machines. Today,
>> ethernet-connected *nix servers have no keyboard, mouse, or even a
>> directly connected terminal.
>
> So how does your tkinter example work in such a server?

Without X-windows available, there would be no point, and it will not
work. I presume including the X window subsystem on a linux (server)
build is optional. Last I knew, all of the linux machines with a
CPython buildbot either do not have X or prohibit the buildbot from
using it.

Compiling _tkinter.c is optional and many (most?) Linux distributions
put tkinter.py, idlelib/*.py, and turtle.py in a separate package. If a
buildbot tries to run gui tests on linux machines without X available,
an exception is raised, something like 'Failed to connect to the X
subsystem'. (It has been 3 years since I cause one of those.)

If the server includes X and tkinter and one connects (likely as admin)
with a X-terminal or emulator, I expect that tk and tkinter should work.
Whether X will let an invisible window keep keyboard focus, I will not
know until someone tries it. Perhaps 99+% of Tcl/tk works the same
across platforms.

> As I don't
> understand the argument that a language shouldn't have a basic keyboard
> API because some computers it could run on might not have a keyboards.

As I and others have said, those keyboard functions are not available on
text terminals. I predict that keyboard functions that so not work on
all systems will never become built-ins. But some are available with an
import.

Python optionally comes with a sophisticated keyboard api. The PSF
(python.org) CPython builds for Windows and Mac include that API. On
Windows, so is the required tcl/tk build. The premise of the subject
line, that Python does not include 'non-blocking keyboard input
functions', is not true.

Some things *can* be simplified. I gave one example previously. While
writing this, I realized that with a little work, I could automate all
the bindings for IDLE menu item event handlers.

> (I've looked at X Windows; bloody hell, it makes Win32/GDI look like
> child's play.)

This may have helped persuade three different language groups to
piggyback on the work of tcl folk. Keeping up with Apple's series of
graphics systems has also been a hassle.

--
Terry Jan Reedy

Marko Rauhamaa

unread,
Oct 27, 2016, 6:42:38 AM10/27/16
to
Terry Reedy <tjr...@udel.edu>:
> Do people on Linux still commonly use full-screen, no window text
> editors like the one I had?

I occasionally switch on one of the alternate VTs, which are not running
any GUI.

However, I constantly use -- in fact, as I type, I'm using -- a program
running in a PTY environment. IOW, the program "thinks" it's running on
a dedicated text-only terminal. The news program (GNUS/emacs in my case)
is not conscious of pixels, keycodes or the mouse. I must use keyboard
commands to navigate.

> On Windows, there are full screen games, but I have never seen a
> full-screen, no-window text application.

As I'm typing, I have two other, unrelated windows on the screen. I'm
using LXDE, which is a classical GUI environment.

It is my understanding that both Windows and Gnome are moving to a
de-facto full-screen GUI. The GUI strongly prefers you opening windows
in full-screen mode.


Marko

BartC

unread,
Oct 27, 2016, 6:42:53 AM10/27/16
to
On 27/10/2016 07:51, Steven D'Aprano wrote:
> On Thursday 27 October 2016 12:12, BartC wrote:
>
>> I don't
>> understand the argument that a language shouldn't have a basic keyboard
>> API because some computers it could run on might not have a keyboards.
>
> That's not the argument. The argument is that Python has a basic keyboard API:
> raw_input (in Python 2) or input (in 3).
>
> This supports 97% of keyboard-based interaction, namely blocking line-based
> text input. Ctrl-C (KeyboardInterrupt) can be co-opted to support maybe another
> one or two percent.
>
> The question is, what are the use-cases for the sorts of key APIs you are
> asking for? Who needs them? Why should it be a language feature?

If a language (or more likely an OS such as Unix) doesn't natively
provide a certain feature, then it's not surprising that 97% of
applications don't use it!

"There's a room in your house with no door to it; how do I get in?"

"There's no need for a door because no one ever uses that room! But you
can get in through the chimney - if you /have/ to."


> Those are not rhetoricial questions.
>
> Python falls neatly into the same niche of languages as (for example) Ruby,
> Javascript, Lua, Swift, Tcl, and (not quite as well) bash, Java, Julia. Which
> of these languages offer non-blocking keyboard input as a standard part of the
> language?

That doesn't surprise me either. Even implementation languages such as C
tend to shy away from the issue. And since C was intimately associated
with Unix, it starts to get even less surprising!

But I seem to remember in a previous thread that Python had some problem
even with line-buffered input. Something to do with only getting a line
of input as a string then needed to do some processing to read
individual elements, IIRC.

(FWIW my own language does strive to have this basic stuff built it. But
getting full keyboard and console handling working as I want it across
both Windows and Linux is challenging. It's a bit easier on Windows as,
even though you're using a console, you have the full resources of the
Win32 API to draw on.

On Linux you can't assume any such resources except some apparently
1970s-style terminal handling, from what I can figure out.)

> Python has no "peek" and "poke" memory access commands either. It's not 1972
> and programming has moved on. The utility of something like this feature is
> very low, the amount of effort needed for a cross-platform solution is very
> high.

My language:

function peek(p,t=byte)=
return makeref(p,t)^
end
...
print peek(0x400'000)

It 'works' on both Windows and Linux, although you need to know what
addresses to safely peek. (I didn't try poke but that's also easy, if
more dangerous. But usually I use such pointer accesses for known data
structures and memory blocks.)

On a machine with a certain memory-mapped device, then this would be ideal.

--
Bartc

Marko Rauhamaa

unread,
Oct 27, 2016, 6:50:25 AM10/27/16
to
BartC <b...@freeuk.com>:

> "There's a room in your house with no door to it; how do I get in?"
>
> "There's no need for a door because no one ever uses that room! But
> you can get in through the chimney - if you /have/ to."

+1

> On Linux you can't assume any such resources except some apparently
> 1970s-style terminal handling, from what I can figure out.)

Correct.

> My language:
>
> function peek(p,t=byte)=
> return makeref(p,t)^
> end
> ...
> print peek(0x400'000)
>
> It 'works' on both Windows and Linux

So how do you draw a big, yellow happy face in the top right corner
using your language?


Marko

BartC

unread,
Oct 27, 2016, 7:15:55 AM10/27/16
to
On 27/10/2016 11:07, Terry Reedy wrote:
> On 10/26/2016 9:12 PM, BartC wrote:
>> On 27/10/2016 00:30, Terry Reedy wrote:

>> So how does your tkinter example work in such a server?
>
> Without X-windows available, there would be no point, and it will not
> work. I presume including the X window subsystem on a linux (server)
> build is optional.

> Compiling _tkinter.c is optional and many (most?) Linux distributions
> put tkinter.py, idlelib/*.py, and turtle.py in a separate package.

I tried your example. It sort of worked but was a bit temperamental when
pressing Rshift.

But I also tried it in a virtual Ubuntu which said that tkinter was not
installed.

And I tried it on Debian on a raspberry pi without X-windows running,
and there it also failed even though it didn't use a window.

So even with a supposedly standard library such as tkinter, relying on
it can give problems. (Apart from to switch between between Tkinter and
tkinter depending on Python version.)

--
Bartc

Steve D'Aprano

unread,
Oct 27, 2016, 7:41:50 AM10/27/16
to
On Thu, 27 Oct 2016 09:42 pm, BartC wrote:

> On 27/10/2016 07:51, Steven D'Aprano wrote:
>> On Thursday 27 October 2016 12:12, BartC wrote:
>>
>>> I don't
>>> understand the argument that a language shouldn't have a basic keyboard
>>> API because some computers it could run on might not have a keyboards.
>>
>> That's not the argument. The argument is that Python has a basic keyboard
>> API: raw_input (in Python 2) or input (in 3).
>>
>> This supports 97% of keyboard-based interaction, namely blocking
>> line-based text input. Ctrl-C (KeyboardInterrupt) can be co-opted to
>> support maybe another one or two percent.
>>
>> The question is, what are the use-cases for the sorts of key APIs you are
>> asking for? Who needs them? Why should it be a language feature?
>
> If a language (or more likely an OS such as Unix) doesn't natively
> provide a certain feature, then it's not surprising that 97% of
> applications don't use it!

Perhaps you should read my statement again.

My claim (plucked from thin air, of course, but nevertheless I'm sticking by
it) is that for 97% of use-cases, when a non-GUI program needs text input
from the user, the *right solution* is blocking line-based text input.

I don't need one character at a time. I want to pause everything else, ask
the user a question, and wait for them to enter an entire line.

And no, I don't want to reinvent the wheel and build up line editing from
character editing myself. I don't want to have to handle backspacing and
navigation myself.



>> Those are not rhetoricial questions.

Feel free to give an answer. Apart from reinventing the wheel and building
functionality that Python already supports, what do you use non-blocking
keyboard input for? Can you give some examples of how you might use it?


>> Python falls neatly into the same niche of languages as (for example)
>> Ruby, Javascript, Lua, Swift, Tcl, and (not quite as well) bash, Java,
>> Julia. Which of these languages offer non-blocking keyboard input as a
>> standard part of the language?
>
> That doesn't surprise me either.

That was a question, not a statement.

You claim that this sort of low-level non-blocking keyboard input is
a "basic" API. Okay, then which other languages offer this?

If Python is the odd one out, if every other programming language bar Python
provides this API, then I'll cheerfully acknowledge that I'm terribly
wrong. I don't understand what this function is good for myself, but
obviously thousands of others do, so I'll learn something from them.

Or... if no other language offers this "basic" API, then maybe its not that
useful or simple, and perhaps not that basic.


> Even implementation languages such as C
> tend to shy away from the issue. And since C was intimately associated
> with Unix, it starts to get even less surprising!

How about Lisp? Scheme? Fortran? Java? C#? Objective-C? Dylan? Forth? Well
I'd completely believe Forth has this, I think you'd like Chuck Moore, I
think the two of you think in similar ways.

Cobol? Hypertalk? Inform 7? Bash? Haskell?

There must be *some* language other than your own that offers this feature,
if it is as obvious, useful, simple and basic and you claim.



> But I seem to remember in a previous thread that Python had some problem
> even with line-buffered input. Something to do with only getting a line
> of input as a string then needed to do some processing to read
> individual elements, IIRC.

O_o

Um, of course it gets a line of input as a text string. What would you
expect to get the user's text as? A bitmap?


> (FWIW my own language does strive to have this basic stuff built it. But
> getting full keyboard and console handling working as I want it across
> both Windows and Linux is challenging. It's a bit easier on Windows as,
> even though you're using a console, you have the full resources of the
> Win32 API to draw on.
>
> On Linux you can't assume any such resources except some apparently
> 1970s-style terminal handling, from what I can figure out.)

And possibly not even that. If your script is running as a cron job, I
believe that there's no terminal attached, and possibly no stdin or stdout.
I don't remember the details.

BartC

unread,
Oct 27, 2016, 9:13:44 AM10/27/16
to
[repost as original disappeared]
On 27/10/2016 12:41, Steve D'Aprano wrote:
> On Thu, 27 Oct 2016 09:42 pm, BartC wrote:

> I don't need one character at a time. I want to pause everything else, ask
> the user a question, and wait for them to enter an entire line.
>
> And no, I don't want to reinvent the wheel and build up line editing from
> character editing myself. I don't want to have to handle backspacing and
> navigation myself.

You're just throwing the ball into someone else's court then.

YOU don't want such features to be part of a language, but you expect
others to be able to write text-mode editors, IDEs, file-managers, games
etc without them?

Presumably you're OK with those features being available in a GUI
environment? So why the discrimination?

Text-apps aren't so common now but I get the impression that you would
never have found this stuff useful.

> Feel free to give an answer. Apart from reinventing the wheel and building
> functionality that Python already supports, what do you use non-blocking
> keyboard input for? Can you give some examples of how you might use it?

I didn't even know what non-blocking meant until this thread.

But suppose you're writing an app such as a debugger, or interpreter, or
anything that keeps going until interrupted or controlled by some key
event. If you're executing a billion instructions per second you don't
want to keep stopping every N instructions to ask the user for any
special requests, or to press Enter to continue.

Is that good enough?

Doubtless your solution would be some large sledgehammer to crack this
particular nut.

> How about Lisp? Scheme? Fortran? Java? C#? Objective-C? Dylan? Forth? Well
> I'd completely believe Forth has this, I think you'd like Chuck Moore, I
> think the two of you think in similar ways.
>
> Cobol? Hypertalk? Inform 7? Bash? Haskell?

> There must be *some* language other than your own that offers this feature,
> if it is as obvious, useful, simple and basic and you claim.

I'm not familiar with that many languages. However if you google for
'<language> non-blocking keyboard' then it seems quite a few people are
interested in the feature!

>> But I seem to remember in a previous thread that Python had some problem
>> even with line-buffered input. Something to do with only getting a line
>> of input as a string then needed to do some processing to read
>> individual elements, IIRC.
>
> O_o
>
> Um, of course it gets a line of input as a text string. What would you
> expect to get the user's text as? A bitmap?

print "Enter 3 numbers: "
readln a,b,c

I'm fairly sure this kind of input was common in plenty of other
languages. But maybe even that is being frowned on now; /that/ wouldn't
surprise me either.

>
>> (FWIW my own language does strive to have this basic stuff built it. But
>> getting full keyboard and console handling working as I want it across
>> both Windows and Linux is challenging. It's a bit easier on Windows as,
>> even though you're using a console, you have the full resources of the
>> Win32 API to draw on.
>>
>> On Linux you can't assume any such resources except some apparently
>> 1970s-style terminal handling, from what I can figure out.)
>
> And possibly not even that. If your script is running as a cron job, I
> believe that there's no terminal attached, and possibly no stdin or stdout.
> I don't remember the details.

The same argument as before. So we don't have print() as part of the
language either before there might not be a stdout?!

The fact is that if I want to run an editor under Linux, I will need a
display, and a keyboard, and I want to have the means to use them.

--
bartc

Marko Rauhamaa

unread,
Oct 27, 2016, 9:24:28 AM10/27/16
to
BartC <b...@freeuk.com>:
> If you're executing a billion instructions per second you don't want
> to keep stopping every N instructions to ask the user for any special
> requests, or to press Enter to continue.

In mobile computing, such wakeups drain the battery.


Marko

Grant Edwards

unread,
Oct 27, 2016, 10:08:34 AM10/27/16
to
Yes, I posted my proposal to the linux-serial list -- which I _think_
is the right one for the pty driver, but that may not have been the
right list.

I suspect proposals like mine generally just get ignored unless you
can show code to back them up.

--
Grant Edwards grant.b.edwards Yow! My face is new, my
at license is expired, and I'm
gmail.com under a doctor's care!!!!

Grant Edwards

unread,
Oct 27, 2016, 10:20:08 AM10/27/16
to
On 2016-10-27, Terry Reedy <tjr...@udel.edu> wrote:

> When I used unix in the 1980s, the full screen ran csh until one started
> another full screen application. MSDOS was the same. Every contemporary
> photo of modern Linux or Mac I have seen has a desktop with windows just
> like Windows. Do people on Linux still commonly use full-screen,

It depends on your definition of "commonly". I do it fairly
regularly, but only for short periods of time while doing system
maintenance stuff.

> no window text editors like the one I had?

Don't know what you mean by "window text editors"

> On Windows, there are full screen games, but I have never seen a
> full-screen, no-window text application.

Just con't conflate "full-screen" with "command-line" or "terminal"
applications. I do use terminal applications all day, every day, but
I mostly run them in terminal emulator windows on top of X11 (that way
I can have lots of terminals of various sizes and shapes).

> Since modern screen are pixel graphics screens, rather than character
> screens, there must be a widget, whether standard with the OS or custom
> to the console, that emulates the old fixed-pitch character screens.

Yes. On Unix they're called terminal emulators, and I use lots of
them them constantly. This post is being edited in one.

> At least on Windows, C Programs that run with the console still get
> characters entered by users and send characters to be displayed.

On Unix, a terminal emulator on an X11/Wayland desktop, a linux video
console, a real serial terminal connected to an RS-232C serial port,
or a "screen" session <https://www.gnu.org/software/screen/> all
behave pretty much the same. The API supported by the pty driver, the
video console tty driver, and the real serial-port tty driver, all
provide a common set of API calls.

--
Grant Edwards grant.b.edwards Yow! I wish I was on a
at Cincinnati street corner
gmail.com holding a clean dog!

Steve D'Aprano

unread,
Oct 27, 2016, 12:13:26 PM10/27/16
to
On Fri, 28 Oct 2016 12:13 am, BartC wrote:

> [repost as original disappeared]
> On 27/10/2016 12:41, Steve D'Aprano wrote:
>> On Thu, 27 Oct 2016 09:42 pm, BartC wrote:
>
>> I don't need one character at a time. I want to pause everything else,
>> ask the user a question, and wait for them to enter an entire line.
>>
>> And no, I don't want to reinvent the wheel and build up line editing from
>> character editing myself. I don't want to have to handle backspacing and
>> navigation myself.
>
> You're just throwing the ball into someone else's court then.


Well of course I am. I don't program my code from bare metal. Nobody with
any sense does that, at least not on a PC. Maybe on embedded systems.

I don't write my own memory management, or my own file system, or my own
process scheduler, or any of the other dozens of things that the OS does
much, much better than anything I can do.

Including line editing.


> YOU don't want such features to be part of a language, but you expect
> others to be able to write text-mode editors, IDEs, file-managers, games
> etc without them?

Ah, now we're getting somewhere: I'm starting to get a hint of what this
feature might be useful for. Okay.

Sure, I'll accept that perhaps this feature of non-blocking keyboard input
does have its use-cases. I might even revise my plucked-from-thin-air
figure of 97% down to allow for "text-mode editors, IDEs, file-managers,
games, etc.".

All of those are big, complex applications. Not Microsoft Office big, or
Oracle database big, but still, you need things like windows, dialog boxes,
animation, sprites, etc. If I were writing any of those, I would absolutely
want to start with an existing framework or library that provides things
like windows, menus, icons, and text input widgets. Whether I'm doing a GUI
application or a text-based application, I wouldn't be writing this stuff
from scratch like it was 1973.

And yes, that's "throwing the ball into someone else's court". There's no
shame in that.


> Presumably you're OK with those features being available in a GUI
> environment? So why the discrimination?

What discrimination? They're available in text environments too. You just
have to use a good text-based UI library, like curses.


> Text-apps aren't so common now but I get the impression that you would
> never have found this stuff useful.
>
>> Feel free to give an answer. Apart from reinventing the wheel and
>> building functionality that Python already supports, what do you use
>> non-blocking keyboard input for? Can you give some examples of how you
>> might use it?
>
> I didn't even know what non-blocking meant until this thread.

When you call (raw_)input(), Python stops processing until the user hits
Enter, at which point it returns whatever they typed.

Earlier, I mistakenly posted a recipe that works similarly: it pauses until
the user hits a key. It *blocks* until the user hits a key, then returns
that key and continues.

A non-blocking function might return None if there is no character in the
input buffer, or that character. I don't know -- I'm not sure how the API
would be designed.


> But suppose you're writing an app such as a debugger, or interpreter, or
> anything that keeps going until interrupted or controlled by some key
> event. If you're executing a billion instructions per second you don't
> want to keep stopping every N instructions to ask the user for any
> special requests, or to press Enter to continue.
>
> Is that good enough?
>
> Doubtless your solution would be some large sledgehammer to crack this
> particular nut.

*shrug*

Python's a pretty high-level language. Not every low-level feature needs to
be part of the Python language. This sounds like something you would write
in a low-level language like C or Rust, turn it into a extension file, and
call it from Python.

You could always check the source code to the Python debugger. Presumably it
already solves this. There has to be *some* solution. After all, operating
systems, text editors, shells, GUI frameworks, etc. all support this.


>> How about Lisp? Scheme? Fortran? Java? C#? Objective-C? Dylan? Forth?
>> Well I'd completely believe Forth has this, I think you'd like Chuck
>> Moore, I think the two of you think in similar ways.
>>
>> Cobol? Hypertalk? Inform 7? Bash? Haskell?
>
>> There must be *some* language other than your own that offers this
>> feature, if it is as obvious, useful, simple and basic and you claim.
>
> I'm not familiar with that many languages. However if you google for
> '<language> non-blocking keyboard' then it seems quite a few people are
> interested in the feature!

*shrug* My very first response suggested that many people ask for this
feature, but then after writing code to implement it, they find they don't
actually need it. Maybe I'm wrong. But if this is so useful, outside of
specialist areas, why do so few languages support it?


>>> But I seem to remember in a previous thread that Python had some problem
>>> even with line-buffered input. Something to do with only getting a line
>>> of input as a string then needed to do some processing to read
>>> individual elements, IIRC.
>>
>> O_o
>>
>> Um, of course it gets a line of input as a text string. What would you
>> expect to get the user's text as? A bitmap?
>
> print "Enter 3 numbers: "
> readln a,b,c

How is the interpreter supposed to know that a, b, c are numbers? What sort
of numbers? 16-bit integers, 80-bit floats, Bignums, complex, Fractions, or
something else?

That's a fairly simple thing for the compiler to do in a language with
static types. It knows that a is a float, b an int, and c another float. So
it can automatically call the appropriate input routines, or conversion
routines, or both.

But in a dynamically typed language, the compiler has no idea what you
expect a, b and c to be. So it returns text, and you can convert it
yourself.


> I'm fairly sure this kind of input was common in plenty of other
> languages. But maybe even that is being frowned on now; /that/ wouldn't
> surprise me either.

Nah, I'm pretty sure that's just a simple issue of whether or not the
compiler knows the type. If it does, then you can say:

x: float;
x = read();

and the compiler can choose the right input routine. Otherwise you have to
do so yourself:

x = read_float();


[...]
>>> On Linux you can't assume any such resources except some apparently
>>> 1970s-style terminal handling, from what I can figure out.)
>>
>> And possibly not even that. If your script is running as a cron job, I
>> believe that there's no terminal attached, and possibly no stdin or
>> stdout. I don't remember the details.
>
> The same argument as before. So we don't have print() as part of the
> language either before there might not be a stdout?!

I didn't say that. I said that print might not work, if you call it from a
cron job. (Or it may -- as I said, I don't remember the details. All I
remember is that cron jobs are run under very restrictive environments.)


> The fact is that if I want to run an editor under Linux, I will need a
> display, and a keyboard, and I want to have the means to use them.

That's nice, but Python is not an Editor Construction Kit that specialises
in writing editors. It can operate under all sorts of conditions, including
some where no editor is possible because there's no keyboard input.

If this feature is so basic, so popular, and so necessary, why hasn't anyone
written the code to provide it and release it for others to use?

BartC

unread,
Oct 27, 2016, 2:10:03 PM10/27/16
to
On 27/10/2016 17:13, Steve D'Aprano wrote:
> On Fri, 28 Oct 2016 12:13 am, BartC wrote:

>> Doubtless your solution would be some large sledgehammer to crack this
>> particular nut.
>
> *shrug*
>
> Python's a pretty high-level language. Not every low-level feature needs to
> be part of the Python language. This sounds like something you would write
> in a low-level language like C or Rust, turn it into a extension file, and
> call it from Python.

I tend not to separate out which applications which are suitable for
low-level and which are better for high-level languages.

And I've seen things like 'import msvcrt', 'import winapi' in Python
code, and then there's all that stuff with ctypes.

It look like other people don't worry about that either. Although if the
language is really unsuitable then they'll find out when it runs too
slowly to be practical.

> You could always check the source code to the Python debugger. Presumably it
> already solves this. There has to be *some* solution. After all, operating
> systems, text editors, shells, GUI frameworks, etc. all support this.

Yes, all those kinds of application need these basic features. Isn't it
odd then that not a single mainstream language provides them as standard?

(From my point of view the discussion has been about any key-at-a-time
events rather than blocking or not. Those are also problematical.)

>> I'm not familiar with that many languages. However if you google for
>> '<language> non-blocking keyboard' then it seems quite a few people are
>> interested in the feature!
>
> *shrug* My very first response suggested that many people ask for this
> feature, but then after writing code to implement it, they find they don't
> actually need it. Maybe I'm wrong. But if this is so useful, outside of
> specialist areas, why do so few languages support it?

For years I've had discussions in comp.lang.c about things that C should
or should not have. What usually happens is that someone comes up with
some crude workaround using macros, so there is less need to have some
feature built-in (and the language fails to a acquire a slick new
enhancement).

But with the usual trouble that everyone then has to re-invent the same
macro but in a different way to everyone else.

The same thing probably happens with a low-level keyboard API. There are
half a dozen ways of achieving the same functionality (with varying
degrees of hassle), so maybe the language doesn't need to provide a
standard solution after all.

You talk about not wanting to re-invent things, but that's exactly what
everyone ends up doing!

>> print "Enter 3 numbers: "
>> readln a,b,c
>
> How is the interpreter supposed to know that a, b, c are numbers? What sort
> of numbers? 16-bit integers, 80-bit floats, Bignums, complex, Fractions, or
> something else?

> But in a dynamically typed language, the compiler has no idea what you
> expect a, b and c to be. So it returns text, and you can convert it
> yourself.

So you tell it what to expect. The above example is from a dynamic
language, and will assume integers unless told otherwise. This:

readln a:"h", b:"r", c:"s"

reads a hex integer, floating point number and a string respectively
(with a default set of separators delimiting the string, or "..." can be
used). Or values can be read one at a time:

readln
read a:"h"

I think this came up when someone wanted to switch from Visual Basic to
Python. The above is not a very sophisticated approach but it is very
simple and intuitive.

--
bartc

Gregory Ewing

unread,
Oct 27, 2016, 5:51:32 PM10/27/16
to
BartC wrote:
> "There's a room in your house with no door to it; how do I get in?"
>
> "There's no need for a door because no one ever uses that room! But you
> can get in through the chimney - if you /have/ to."

It's not like that. The room *does* have a door, it's just
that it's in different places in different houses, and may
require a different key to open it.

> function peek(p,t=byte)=
> return makeref(p,t)^
> end

You can achieve similar things in Python using ctypes if
you really need to live that dangerously.

--
Greg

BartC

unread,
Oct 27, 2016, 6:02:40 PM10/27/16
to
On 27/10/2016 19:09, BartC wrote:
> On 27/10/2016 17:13, Steve D'Aprano wrote:
>> On Fri, 28 Oct 2016 12:13 am, BartC wrote:

>>> print "Enter 3 numbers: "
>>> readln a,b,c
>>
>> How is the interpreter supposed to know that a, b, c are numbers? What
>> sort
>> of numbers? 16-bit integers, 80-bit floats, Bignums, complex,
>> Fractions, or
>> something else?
>
>> But in a dynamically typed language, the compiler has no idea what you
>> expect a, b and c to be. So it returns text, and you can convert it
>> yourself.

I notice that when it comes to reading command-line arguments, then
Python's sys.argv presents them as a list, not one long string.

And the list is just a series of strings, so needing to know whether any
parameter was a number or whatever obviously wasn't a problem. It just
makes each item into a string (actually that might be a better default
than mine).

This is a very similar issue to reading items from a line of user input.

So why doesn't sys.argv just return a single string if a line is so easy
to parse?

(That's exactly what Windows' WinMain() function does - optional entry
point for executables under Windows. But C's main() entry point chops
the command line up into separate strings like Python.

Also - this might some bearing on why Python does it that way - under
Linux, a parameter such as *.py is replaced by the names of ALL the
files that end in .py. (I was rather astonished when I find out. But
I've recently had to deal with a directory containing 3,400,000 files so
having a single "*" converted into 3.4 million filenames would be
unwelcome.))

--
Bartc


Chris Angelico

unread,
Oct 27, 2016, 6:31:17 PM10/27/16
to
On Fri, Oct 28, 2016 at 9:02 AM, BartC <b...@freeuk.com> wrote:
>
> I notice that when it comes to reading command-line arguments, then Python's
> sys.argv presents them as a list, not one long string.
>
> And the list is just a series of strings, so needing to know whether any
> parameter was a number or whatever obviously wasn't a problem. It just makes
> each item into a string (actually that might be a better default than mine).
>
> This is a very similar issue to reading items from a line of user input.
>
> So why doesn't sys.argv just return a single string if a line is so easy to
> parse?

Because the OS provides a series of strings, not just one string. When
you exec to a process, you provide multiple arguments, not a single
combined string.

ChrisA

BartC

unread,
Oct 27, 2016, 7:45:19 PM10/27/16
to
On 27/10/2016 23:31, Chris Angelico wrote:
> On Fri, Oct 28, 2016 at 9:02 AM, BartC <b...@freeuk.com> wrote:
>>
>> I notice that when it comes to reading command-line arguments, then Python's
>> sys.argv presents them as a list, not one long string.
>>
>> And the list is just a series of strings, so needing to know whether any
>> parameter was a number or whatever obviously wasn't a problem. It just makes
>> each item into a string (actually that might be a better default than mine).
>>
>> This is a very similar issue to reading items from a line of user input.
>>
>> So why doesn't sys.argv just return a single string if a line is so easy to
>> parse?
>
> Because the OS provides a series of strings, not just one string.

I don't think that's the case on Windows. Perhaps on Unix.

When
> you exec to a process, you provide multiple arguments, not a single
> combined string.

Really, there could be dozens of arguments? Windows' CreateProcess() (if
that's the same thing) has ten of which one is the command-line as a
single string, while C's system() just has one.

This might just be one of those Unixisms that doesn't apply on all
platforms.


--
Bartc

Chris Angelico

unread,
Oct 27, 2016, 8:08:50 PM10/27/16
to
system() passes its argument through to the shell for parsing. In the
same way, Python's Popen constructor can either take a list of
strings, or a single string.

> This might just be one of those Unixisms that doesn't apply on all
> platforms.

Or maybe the single-string form is a Windowsism that doesn't apply on
any other platforms. Let me go dig up my OS/2 Assembly Language
Programming Reference...

ChrisA

BartC

unread,
Oct 27, 2016, 8:21:12 PM10/27/16
to
OK. What comes out of this is that single- or multi-string ways passing
the contents of a line of input are both workable.

So perhaps my way of allowing more general line-input to be read an
item-at-a-time instead of as a single string isn't that off-the-wall either.

--
Bartc

Michael Torrie

unread,
Oct 28, 2016, 1:05:34 AM10/28/16
to
On 10/27/2016 04:07 AM, Terry Reedy wrote:
> As I and others have said, those keyboard functions are not available on
> text terminals. I predict that keyboard functions that so not work on
> all systems will never become built-ins. But some are available with an
> import.

Sure you can't get a keyboard scancode when you're in terminal. But you
can get "keystrokes" as it were, without having to read an entire line
from standard in. I use editors and programs all the time which are
interactive (they don't buffer keyboard input into lines) in the
terminal. vim, nano, pico, mc, etc.

Is this not what BartC is talking about? A way of reading in
"keystrokes" in a terminal. Whether this is coming from a canned file
via a pipe or a real keyboard and screen attached to a TTY doesn't
really matter. There are implementations of curses for the Windows
console, but I doubt they are supported by the python curses module.
But at least curses provides a means of doing this for programmers in a
unix environment.

For mostly nostalgic reasons I play around with the FreeBASIC compiler
and it tries to faithfully emulate the old key input that BASICs of yore
did. Such as inkey$ (which returns nothing if no keystroke is
available). It runs more or less as advertised in a terminal window on
Linux, or the console on Windows. They even go so far as to emulate the
old MS-DOS keycodes for things like arrow keys so that old code can
still run faithfully. I think this is the sort of thing BartC would
like to see in Python. It's certainly possible, even on terminals, but
unlikely to happen for reasons that have been well-stated already by others.

> Python optionally comes with a sophisticated keyboard api. The PSF
> (python.org) CPython builds for Windows and Mac include that API. On
> Windows, so is the required tcl/tk build. The premise of the subject
> line, that Python does not include 'non-blocking keyboard input
> functions', is not true.

I would think curses would provide the needed functionality without
tkinter or an X server. It's limited in that only key combinations that
have control code representation can be detected, but you can definitely
use arrow keys, function keys, etc. And I've seen curses interactive
games so I know they can be read without blocking the whole program.

Michael L Torrie

unread,
Oct 28, 2016, 1:16:42 AM10/28/16
to
On 10/27/2016 11:05 PM, Michael Torrie wrote:
> On 10/27/2016 04:07 AM, Terry Reedy wrote:
>> As I and others have said, those keyboard functions are not available on
>> text terminals. I predict that keyboard functions that so not work on
>> all systems will never become built-ins. But some are available with an
>> import.

> Is this not what BartC is talking about?

I see that BartC is wanting to detect keys like left shift and right
shift. Even back in QB MS-DOS days when the program was running very
close to bare metal that wasn't possible using a QB construct.

Christian Gollwitzer

unread,
Oct 28, 2016, 1:34:48 AM10/28/16
to
Am 28.10.16 um 07:05 schrieb Michael Torrie:
> On 10/27/2016 04:07 AM, Terry Reedy wrote:
>> As I and others have said, those keyboard functions are not available on
>> text terminals. I predict that keyboard functions that so not work on
>> all systems will never become built-ins. But some are available with an
>> import.
>
> Sure you can't get a keyboard scancode when you're in terminal. But you
> can get "keystrokes" as it were, without having to read an entire line
> from standard in. I use editors and programs all the time which are
> interactive (they don't buffer keyboard input into lines) in the
> terminal. vim, nano, pico, mc, etc.
>
> Is this not what BartC is talking about? A way of reading in
> "keystrokes" in a terminal.

You can do this, if you want, by setting the terminal to raw mode. On
Linux and OSX you can call "stty" to do that which should not be too
difficult. Then you need a second thread or switch to non-blocking I/O
from stdin, maybe asyncio can do that. On Windows OTOH you have to
switch to a whole different API instead of reading from a file descripor
AFAIK.

I still believe that it is not a "basic functionality". You need it, if
you want to program a text editor or similar thing, but without using a
real GUI. This is a small niche. It is both easier and more functional
to use a real GUI library.

Christian

Marko Rauhamaa

unread,
Oct 28, 2016, 3:33:58 AM10/28/16
to
Christian Gollwitzer <auri...@gmx.de>:
> I still believe that it is not a "basic functionality". You need it,
> if you want to program a text editor or similar thing, but without
> using a real GUI. This is a small niche.

I disagree. It's a very large group of programs. For example, CPython's
input() function puts the terminal in character mode to support
emacs-style editing keys on Linux. And of course, CPython's REPL reader
does it as well.

CPython does that via GNU readline:

<URL: https://docs.python.org/3/library/readline.html>

> It is both easier and more functional to use a real GUI library.

Well, CPython doesn't do that...


Marko

Christian Gollwitzer

unread,
Oct 28, 2016, 3:52:04 AM10/28/16
to
Am 28.10.16 um 09:33 schrieb Marko Rauhamaa:
> Christian Gollwitzer <auri...@gmx.de>:
>> I still believe that it is not a "basic functionality". You need it,
>> if you want to program a text editor or similar thing, but without
>> using a real GUI. This is a small niche.
>
> I disagree. It's a very large group of programs. For example, CPython's
> input() function puts the terminal in character mode to support
> emacs-style editing keys on Linux. And of course, CPython's REPL reader
> does it as well.
>
> CPython does that via GNU readline:
>
> <URL: https://docs.python.org/3/library/readline.html>

You are right, readline is a very important application that uses raw
terminal input. What Bart is complaining, currently you can't easily
implement something like readline in Python from scratch - where you
intercept all keystrokes - as opposed to using readline as it is. I am
just not convinced that so many people need to implement something like
readline.

>> It is both easier and more functional to use a real GUI library.
>
> Well, CPython doesn't do that...

But it doesn't intercept each keystroke, either. You could argue that
readline IS a "GUI" library, and you get all the benefits from using it
- it is used in multiple places, so the user is familiar with it, you
don't need to fiddle with low-leve stuff like different terminal escape
sequences etc.

Christian

Marko Rauhamaa

unread,
Oct 28, 2016, 4:59:37 AM10/28/16
to
Christian Gollwitzer <auri...@gmx.de>:

> Am 28.10.16 um 09:33 schrieb Marko Rauhamaa:
> I am just not convinced that so many people need to implement
> something like readline.

I don't know. How would you implement "less" in Python? How would you
implement "nethack" in Python?

Well, Python does offer it all. You do it like you would in C. You set
the terminal mode.

When in Linux, do as the Linux system programmers do. I'm glad Python
hasn't tried to hide Linux under shoddy abstractions -- or at least I'm
not forced to use them.


Marko

Christian Gollwitzer

unread,
Oct 28, 2016, 5:22:24 AM10/28/16
to
Am 28.10.16 um 10:59 schrieb Marko Rauhamaa:
> Christian Gollwitzer <auri...@gmx.de>:
>
>> Am 28.10.16 um 09:33 schrieb Marko Rauhamaa:
>> I am just not convinced that so many people need to implement
>> something like readline.
>
> I don't know. How would you implement "less" in Python? How would you
> implement "nethack" in Python?

On my system:

Apfelkiste:~ chris$ otool -L /usr/bin/less
/usr/bin/less:
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current
version 5.4.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 1225.0.0)

So "less" in C uses ncurses. You can do the same in Python, "import
curses" - instead of fiddling with terminal escape characters you leave
that to a library, just like less does it.

> Well, Python does offer it all. You do it like you would in C. You set
> the terminal mode.
>
> When in Linux, do as the Linux system programmers do. I'm glad Python
> hasn't tried to hide Linux under shoddy abstractions -- or at least I'm
> not forced to use them.

Agreed.

Christian

BartC

unread,
Oct 28, 2016, 6:02:37 AM10/28/16
to
On 28/10/2016 10:22, Christian Gollwitzer wrote:
> Am 28.10.16 um 10:59 schrieb Marko Rauhamaa:

> So "less" in C uses ncurses. You can do the same in Python, "import
> curses" - instead of fiddling with terminal escape characters you leave
> that to a library, just like less does it.

As I commented further up the thread, I tried 'import curses' in Windows
and it said it couldn't find the module.

(Looking at docs.python.org: "No one has made a Windows port of the
curses module".)

If you intend this keyboard handling to be a very minor part of a larger
application, you don't want it falling over the first time someone tries
to use it.


--
Bartc

Marko Rauhamaa

unread,
Oct 28, 2016, 6:30:31 AM10/28/16
to
Christian Gollwitzer <auri...@gmx.de>:

> Am 28.10.16 um 10:59 schrieb Marko Rauhamaa:
>> I don't know. How would you implement "less" in Python? How would you
>> implement "nethack" in Python?
>
> On my system:
>
> Apfelkiste:~ chris$ otool -L /usr/bin/less
> /usr/bin/less:
> /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0,
> current version 5.4.0)
> /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
> version 1225.0.0)
>
> So "less" in C uses ncurses.

On mine (Fedora 24):

========================================================================
$ ldd $(which less)
linux-vdso.so.1 (0x00007ffdbbb79000)
libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007f8d72678000)
libc.so.6 => /lib64/libc.so.6 (0x00007f8d722b6000)
/lib64/ld-linux-x86-64.so.2 (0x000055e31be7e000)
========================================================================

Notably missing is: /usr/lib64/libncurses.so.6


Marko

Marko Rauhamaa

unread,
Oct 28, 2016, 6:35:21 AM10/28/16
to
BartC <b...@freeuk.com>:

> On 28/10/2016 10:22, Christian Gollwitzer wrote:
>> So "less" in C uses ncurses. You can do the same in Python, "import
>> curses" - instead of fiddling with terminal escape characters you
>> leave that to a library, just like less does it.
>
> As I commented further up the thread, I tried 'import curses' in
> Windows and it said it couldn't find the module.

I can't comment on Windows. I'm only talking about Linux. Christian was
talking about OSX.

As for why there isn't a facility that would do it on all platforms,
that question is akin to: Oh, why can't everybody just speak English?

> If you intend this keyboard handling to be a very minor part of a
> larger application, you don't want it falling over the first time
> someone tries to use it.

Didn't someone in this thread already mention a way to do it in Windows?


Marko

BartC

unread,
Oct 28, 2016, 6:58:00 AM10/28/16
to
There are a million ways to do it. But you don't want a million, you
want one.

Otherwise "A" will now need to create a new library which presents a
common API to the application but internally takes care of the
differences between platforms. But now you have an extra dependency for
your app. Your own code is not a problem; you just bundle it with the
app. But platform-dependent dependencies (if that makes sense) can be a
problem.

And "B" who wants to use the same functionality will have to find their
own solution, and so on.

This is exactly the sort of 're-inventing the wheel' that not including
the functionality in the language was supposed to avoid!

--
Bartc

Steve D'Aprano

unread,
Oct 28, 2016, 7:05:27 AM10/28/16
to
On Fri, 28 Oct 2016 09:02 am, BartC wrote:

> I notice that when it comes to reading command-line arguments, then
> Python's sys.argv presents them as a list, not one long string.

Yes, just like the shell presents it to Python. It would be silly for Python
to take the list of strings it receives, join them into a single string,
and then have the user split it up again.

Not to mention the possible ambiguity if any of the arguments contain
spaces.



> And the list is just a series of strings, so needing to know whether any
> parameter was a number or whatever obviously wasn't a problem. It just
> makes each item into a string (actually that might be a better default
> than mine).
>
> This is a very similar issue to reading items from a line of user input.
>
> So why doesn't sys.argv just return a single string if a line is so easy
> to parse?

I don't understand your question. Who said strings are necessarily easy to
parse?

Strings *might* be easy to parse if you know what the string represents
ahead of time: "a sequence of integers, separated by spaces" is easy. But
not all data is that simple: "a valid Perl program" is notoriously
difficult. As they say, nothing but Perl can parse Perl. Likewise for C++.

The shell cannot make many assumptions about the data is it passing on. All
it knows is that it has received a sequence of characters. It cannot know
what the receiver intends to do with them, or what those characters
represent. Just because the characters are "1234" doesn't mean that they
represent the integer 1234.

I say *many* assumptions rather than *any* because, of course, any shell is
permitted to make whatever assumptions it likes! If you don't like the
shell's rules, use a different shell! But in general, shells tend towards
*minimal* interpretation of arguments: spaces separate arguments unless
escaped, for example, and a handful of special characters like * ? & ! are
given special meaning.


> (That's exactly what Windows' WinMain() function does - optional entry
> point for executables under Windows. But C's main() entry point chops
> the command line up into separate strings like Python.
>
> Also - this might some bearing on why Python does it that way - under
> Linux, a parameter such as *.py is replaced by the names of ALL the
> files that end in .py.

That's a feature of the shell. I expect you're probably using bash, as
that's the most commonly used shell, but other shells do the same.

There's probably a way to turn that off, but I don't know it. If you want to
pass a literal star * you need to escape it so that the shell won't treat
it as a glob and expanding it: \*.py or "*.py" will probably work.

(And yes, shell escaping is one of the more arcane and tricky part of Unix
shell scripting.)

Terry Reedy

unread,
Oct 28, 2016, 8:13:07 AM10/28/16
to
On 10/28/2016 1:05 AM, Michael Torrie wrote:

> Sure you can't get a keyboard scancode when you're in terminal.

As you note in your followup, Marko and Bart want to be able to respond,
for instance, to left and right shift, separately and differently.
Ascii terminals only send and receive ascii characters, including
control 'characters'. Enhanced ('smart') terminals also receive and, I
presume, send escape sequences representing editing actions Last I knew
a couple of decades ago, there were no ansi code sequences for shift key
presses. So responding to these requires that something in the process
have access to them.

> But you can get "keystrokes" as it were, without having to read an
entire line
> from standard in. ...

> Is this not what BartC is talking about? A way of reading in
> "keystrokes" in a terminal.

The only specification he has given is reference to the BASIC INKEY$
variable. I don't know how consistent this was across different BASICs.
I looked in Microsoft's GW-BASIC reference and it says that it returns
'', 'x', or '0x'. This latter represents an extended code "described in
Appendix C'. However, Appendix C only lists the standard ASCII codes
000 to 128. So I do not know what else was available and would not know
from this book how to emulate GW-BASIC INKEY$.

With tk, everything is available that is standard on any of the major
systems. A key event includes widget name, key name (a single char for
char keys, a capitalized name otherwise), keycode, and x,y pixel
position of the mouse relative to the widget. A tkinter inkey()
function might work as follows:

#------------------------------------------------------------
"""tk_inkey.py, 2016 Oct 26
(C) Terry Jan Reedy
Emulate BASIC INKEY$ function/variable as Python inkey() function.
"""
# Create inkey function
from collections import deque
import tkinter as tk
root = tk.Tk()

def setup_inkey(widget):
# Key values must be stored so inkey can access them.
# If inkey were always called faster than a person can type,
# a single nonlocal would suffice. However, since update()
# processes all pending keys, a queue is needed.
q = deque()

def storekeyname(event):
q.append(event.keysym) # or other key description
return 'break' # swallow the event

widget.bind('<Key>', storekeyname)

def inkey():
widget.update() # process all pending keys
return q.popleft() if q else ''

return inkey

inkey = setup_inkey(root)

# Test inkey in simulated use.
import time

display = tk.Label(root, text='No Key', width=30)
display.pack()
root.update()

while True:
time.sleep(.3) # 'do some calculation'
try:
c = inkey()
except tk.TclError:
break
if c:
display['text'] = c
#---------------------------------------------------------------

This runs *without* blocking root.mainloop(), but rather with
root.update() within inkey(). So it can be used within normal code. As
I said before, this could be coupled with a tk Text that emulates a
console, with custom print and input functions, so it would look like
and work like a console application that responds to keypresses.


The use model of INKEY$ is that the programmer must branch to code
blocks or functions according to the value returned. An alternative
'non-blocking' use model is that the programmer binds functions to
particular events and lets the framework do the dispatching. One
difference is when the function is called. A generalized version of the
key handler above could triage key presses into those handled
immediately, those enqueued for later handling, and those ignored. The
decision whether to swallow or pass on events could be different for
different events.

--
Terry Jan Reedy

Chris Angelico

unread,
Oct 28, 2016, 8:28:57 AM10/28/16
to
On Fri, Oct 28, 2016 at 11:12 PM, Terry Reedy <tjr...@udel.edu> wrote:
> The only specification he has given is reference to the BASIC INKEY$
> variable. I don't know how consistent this was across different BASICs. I
> looked in Microsoft's GW-BASIC reference and it says that it returns '',
> 'x', or '0x'. This latter represents an extended code "described in
> Appendix C'. However, Appendix C only lists the standard ASCII codes 000 to
> 128. So I do not know what else was available and would not know from this
> book how to emulate GW-BASIC INKEY$.

The return values from INKEY$ are CHR$(0) + "H" for up-arrow, "P" for
down-arrow, and I think "K" and "L" for left and right. F1 is CHR$(0)
+ ";", and the next nine function keys are the subsequent ASCII
characters (";<=>?@ABCD"), although F11 and F12 are different, and I
don't remember what they are. The codes don't really have any meaning
in ASCII - they're just the scan codes, as represented in strings.
(CHR$(0) is equivalent to "\0" in saner languages.)

This is from memory, but I spent a *ton* of time in BASIC in my
earlier days, and there are things you never forget :)

ChrisA

Christian Gollwitzer

unread,
Oct 28, 2016, 9:51:12 AM10/28/16
to
Am 28.10.16 um 12:30 schrieb Marko Rauhamaa:
Interesting. So your less does it in a different way than mine. I peeked
into the sources, and it seems that less uses either tinfo, xcurses,
ncursesw, ncurses, curses, termcap or termlib on nNix-like systems. On
Windows it uses WIN32getch(). So there is no "one obvious way" to do
this in C, but a large variety of options - just like in Python.

Christian

Grant Edwards

unread,
Oct 28, 2016, 10:29:11 AM10/28/16
to
He didn't say "when you CreateProcess()" or "when you system()", he
said "when you exec". Take a look at the exec man page:

http://man7.org/linux/man-pages/man3/exec.3.html

Note that the arguments are passed as arbitrary length arrays of
character pointers.

> This might just be one of those Unixisms that doesn't apply on all
> platforms.

By using the name of a Unix system call, one might think so.

--
Grant Edwards grant.b.edwards Yow! I'm a fuschia bowling
at ball somewhere in Brittany
gmail.com

Chris Angelico

unread,
Oct 28, 2016, 11:04:05 AM10/28/16
to
On Sat, Oct 29, 2016 at 1:54 AM, Dennis Lee Bieber
<wlf...@ix.netcom.com> wrote:
> https://en.wikibooks.org/wiki/QBasic/Advanced_Input
> indicates that INKEY$ doesn't even test the keyboard for presses, but is
> only retrieving the next item from the keyboard input /buffer/ (which that
> article goes on to mention used to be part of a dedicated hardware chip,
> but now is a software/interrupt maintained buffer).

True, but in practice, it's the same thing. The keyboard buffer ring
gets populated by the interrupt handler, and INKEY$ looks at the
buffer, sees if it's empty (return ""), and if not, consumes and
returns one key.

> And it defines the extended return value as the "scan code" for the
> keyboard. Which would just be a number assigned to the key position, and
> might (back in those days) have had different values going from machine to
> machine. Most of the modifier keys (shift, control) in those days did not
> produce their own codes.

Yes, but who ever writes programs that run on multiple different
computers? Just hard-code those scan codes everywhere, it'll be fine!

ChrisA
born in those lackadaisical days when "Extended ASCII" was a single
thing, because the rest of the world didn't exist

Michael Torrie

unread,
Oct 28, 2016, 11:17:07 AM10/28/16
to
And FreeBASIC faithfully emulates this for all its supported platforms,
terminals or graphics mode (fakes a screen buffer in a window).

I'm sure someone could make a python module that offered inkey() on any
platform in terminals and consoles based on raw input, or using win32
console api calls. But I am not sure it belongs in the standard
library. Nor am I sure what codes should be returned.

BartC

unread,
Oct 28, 2016, 11:28:14 AM10/28/16
to
On 28/10/2016 15:28, Grant Edwards wrote:
> On 2016-10-27, BartC <b...@freeuk.com> wrote:
>> On 27/10/2016 23:31, Chris Angelico wrote:
>
>>> When you exec to a process, you provide multiple arguments, not a
>>> single combined string.
>>
>> Really, there could be dozens of arguments? Windows' CreateProcess() (if
>> that's the same thing) has ten of which one is the command-line as a
>> single string, while C's system() just has one.
>
> He didn't say "when you CreateProcess()" or "when you system()", he
> said "when you exec". Take a look at the exec man page:
>
> http://man7.org/linux/man-pages/man3/exec.3.html
>
> Note that the arguments are passed as arbitrary length arrays of
> character pointers.
>
>> This might just be one of those Unixisms that doesn't apply on all
>> platforms.
>
> By using the name of a Unix system call, one might think so.

Python is cross-platform, isn't it?

--
bartc

Terry Reedy

unread,
Oct 28, 2016, 1:51:01 PM10/28/16
to
On 10/28/2016 11:03 AM, Chris Angelico wrote:
> On Sat, Oct 29, 2016 at 1:54 AM, Dennis Lee Bieber
> <wlf...@ix.netcom.com> wrote:
>> https://en.wikibooks.org/wiki/QBasic/Advanced_Input
>> indicates that INKEY$ doesn't even test the keyboard for presses, but is
>> only retrieving the next item from the keyboard input /buffer/ (which that
>> article goes on to mention used to be part of a dedicated hardware chip,
>> but now is a software/interrupt maintained buffer).
>
> True, but in practice, it's the same thing. The keyboard buffer ring
> gets populated by the interrupt handler, and INKEY$ looks at the
> buffer, sees if it's empty (return ""), and if not, consumes and
> returns one key.

'ring bugger' implies a finite limit tot he size of the queue. Do
either of you know what it is?

>> And it defines the extended return value as the "scan code" for the
>> keyboard. Which would just be a number assigned to the key position, and
>> might (back in those days) have had different values going from machine to
>> machine. Most of the modifier keys (shift, control) in those days did not
>> produce their own codes.

If I were to write inkey() for my own use or as part of a tk console
module, I would stick with returning either the character or a mostly
machine and OS independent name.

--
Terry Jan Reedy

Chris Angelico

unread,
Oct 28, 2016, 1:56:15 PM10/28/16
to
On Sat, Oct 29, 2016 at 4:50 AM, Terry Reedy <tjr...@udel.edu> wrote:
> On 10/28/2016 11:03 AM, Chris Angelico wrote:
>>
>> On Sat, Oct 29, 2016 at 1:54 AM, Dennis Lee Bieber
>> <wlf...@ix.netcom.com> wrote:
>>>
>>> https://en.wikibooks.org/wiki/QBasic/Advanced_Input
>>> indicates that INKEY$ doesn't even test the keyboard for presses, but is
>>> only retrieving the next item from the keyboard input /buffer/ (which
>>> that
>>> article goes on to mention used to be part of a dedicated hardware chip,
>>> but now is a software/interrupt maintained buffer).
>>
>>
>> True, but in practice, it's the same thing. The keyboard buffer ring
>> gets populated by the interrupt handler, and INKEY$ looks at the
>> buffer, sees if it's empty (return ""), and if not, consumes and
>> returns one key.
>
>
> 'ring bugger' implies a finite limit tot he size of the queue. Do either of
> you know what it is?
>

16 slots, each 16 bits (8 bits character, 8 bits scan code). I think
it filled at 15, though, from memory; if the head and tail pointers
are equal, the buffer is empty, ergo the buffer cannot completely
fill. That's where the classic "bip" of keyboard-buffer-full came
from.

ChrisA

Steve D'Aprano

unread,
Oct 28, 2016, 8:13:18 PM10/28/16
to
On Sat, 29 Oct 2016 02:03 am, Chris Angelico wrote:

> born in those lackadaisical days when "Extended ASCII" was a single
> thing, because the rest of the world didn't exist

I know you're being sarcastic, but "extended ASCII" *never* was a single
thing, even for Americans who ignored the rest of the world. You had IBM PC
extended ASCII, Apple Macintosh extended ASCII, Hewlett-Packard extended
ASCII, Atari extended ASCII ("ATASCII"), Commodore extended ASCII
("PETSCII"), and more.

Steve D'Aprano

unread,
Oct 28, 2016, 8:32:20 PM10/28/16
to
On Sat, 29 Oct 2016 02:28 am, BartC wrote:

>> By using the name of a Unix system call, one might think so.
>
> Python is cross-platform, isn't it?

The os module isn't. It is specifically designed for OS-specific functions.

There's lots of OS-specific functionality in Python. In general, Python
won't make any promises that the OS doesn't, nor will it generally offer
any feature that the OS doesn't. In particular, system calls are only
available on platforms that provide that system call. (Duh.)

So no Windows system calls on Unix, and no Unix system calls on Windows.

Steve D'Aprano

unread,
Oct 28, 2016, 9:04:35 PM10/28/16
to
On Fri, 28 Oct 2016 05:09 am, BartC wrote:

> And I've seen things like 'import msvcrt', 'import winapi' in Python
> code, and then there's all that stuff with ctypes.

Right. Not everything needs to be a feature of the language itself,
especially if it is operating system dependent and can be delegated to the
OS.


>> You could always check the source code to the Python debugger. Presumably
>> it already solves this. There has to be *some* solution. After all,
>> operating systems, text editors, shells, GUI frameworks, etc. all support
>> this.
>
> Yes, all those kinds of application need these basic features. Isn't it
> odd then that not a single mainstream language provides them as standard?

Not really. I don't see this is as a useful language feature.



> (From my point of view the discussion has been about any key-at-a-time
> events rather than blocking or not. Those are also problematical.)

Key-at-a-time events are solved. I've already linked to a working solution
for that, which supports both Windows and Unix/Linux. Its not in the base
language because its not as useful as you insist, and those who need it
have alternatives. Not everything needs to be in the base language.



>>> I'm not familiar with that many languages. However if you google for
>>> '<language> non-blocking keyboard' then it seems quite a few people are
>>> interested in the feature!
>>
>> *shrug* My very first response suggested that many people ask for this
>> feature, but then after writing code to implement it, they find they
>> don't actually need it. Maybe I'm wrong. But if this is so useful,
>> outside of specialist areas, why do so few languages support it?
>
> For years I've had discussions in comp.lang.c about things that C should
> or should not have. What usually happens is that someone comes up with
> some crude workaround using macros, so there is less need to have some
> feature built-in (and the language fails to a acquire a slick new
> enhancement).

Bart, don't be naive. The C language isn't going to "acquire a slick new
enhancement" based on a few emails on compl.lang.c. C is an ISO-standard.
Stability of the language, the fact that you have a known set of
functionality, is precisely why it was made a standard in the first place:
to discourage the sort of "wouldn't it be cool if..." pile up of features
and bloat and ever-changing language specs.

You are *incredibly* privileged to do all your work on your own custom
programming languages, where you get to choose what platforms to support
("whatever PC I am using this year") and have a user-base of exactly one
user ("me").


> But with the usual trouble that everyone then has to re-invent the same
> macro but in a different way to everyone else.
>
> The same thing probably happens with a low-level keyboard API. There are
> half a dozen ways of achieving the same functionality (with varying
> degrees of hassle), so maybe the language doesn't need to provide a
> standard solution after all.
>
> You talk about not wanting to re-invent things, but that's exactly what
> everyone ends up doing!

So what?

That sounds harsh, and it is intended to. Screw 'em. Who cares if a dozen
people have to write their own three line function to do something?

The Python core developers are not a magic genie that you get to snap your
fingers and they will do your coding for you. They are (for the most part,
with one or two part-time exceptions) volunteers who take time out of their
busy lives to work on Python. Time that they might otherwise be spending
with their families or making a living. Have you seen the bug tracker? They
don't have either the time or manpower to keep up with the number of
enhancements and bug fixes requested.

Any new feature has to be weighed up by these volunteers:

- Nobody is paying me to do this. Do I care about this feature
enough to implement it when I could work on something more
important instead?

- If I add this new feature, will people actually use it? Or is
this something that sounds important but in practice will be
used by hardly anyone? Am I wasting my time?

- Even useful features have cost. They add to the cost of the
Python compiler and standard library: more code, more bugs,
more documentation, more tests, more features to learn, more
complex code base, and larger downloads. Is it worth the cost?

The size of Python isn't important to *you* on your fancy PC with entire
gigabytes of hard drive, but to people interested in running Python on
embedded hardware and micro-computers, every kilobyte counts.

- And more important than the physical size is the size and shape
of the learning curve, both to use Python and to maintain it.
Every new feature makes the language bigger and raises the
barrier to entry for new users before they can say they have
mastered the language.

So no, not every feature belongs in the core language, or even in the
standard library.



>>> print "Enter 3 numbers: "
>>> readln a,b,c
>>
>> How is the interpreter supposed to know that a, b, c are numbers? What
>> sort of numbers? 16-bit integers, 80-bit floats, Bignums, complex,
>> Fractions, or something else?
>
>> But in a dynamically typed language, the compiler has no idea what you
>> expect a, b and c to be. So it returns text, and you can convert it
>> yourself.
>
> So you tell it what to expect. The above example is from a dynamic
> language, and will assume integers unless told otherwise. This:
>
> readln a:"h", b:"r", c:"s"
>
> reads a hex integer, floating point number and a string respectively
> (with a default set of separators delimiting the string, or "..." can be
> used). Or values can be read one at a time:
>
> readln
> read a:"h"

Here's an alternative spelling:

readh a
readr b
reads c

Or if you prefer more Pythonic syntax:

a = read_hexint()
b = read_float()
c = read_string()


And we're back to what started with.


> I think this came up when someone wanted to switch from Visual Basic to
> Python. The above is not a very sophisticated approach but it is very
> simple and intuitive.

Intuitive to whom? To me, it just looks weird.

Chris Angelico

unread,
Oct 28, 2016, 10:56:02 PM10/28/16
to
On Sat, Oct 29, 2016 at 11:13 AM, Steve D'Aprano
<steve+...@pearwood.info> wrote:
> On Sat, 29 Oct 2016 02:03 am, Chris Angelico wrote:
>
>> born in those lackadaisical days when "Extended ASCII" was a single
>> thing, because the rest of the world didn't exist
>
> I know you're being sarcastic, but "extended ASCII" *never* was a single
> thing, even for Americans who ignored the rest of the world. You had IBM PC
> extended ASCII, Apple Macintosh extended ASCII, Hewlett-Packard extended
> ASCII, Atari extended ASCII ("ATASCII"), Commodore extended ASCII
> ("PETSCII"), and more.
>

I know; the non-rest-of-world mentality is a consequence of writing
code solely for an IBM PC, as well as solely for your locale. We used
what is today called codepage 437 - why would anyone need anything
else? I guess, in theory, people who speak Greek or Russian would need
to use something else. But then they miss out on all these awesome box
drawing characters, and.... bah, that doesn't matter anyway, does it.

Took the rise of the web before I, as a programmer and as a person,
got a proper appreciation for i18n. And even then it was slow going.
Way better for someone to learn the right way first.

ChrisA

BartC

unread,
Oct 29, 2016, 7:53:52 AM10/29/16
to
On 29/10/2016 02:04, Steve D'Aprano wrote:
> On Fri, 28 Oct 2016 05:09 am, BartC wrote:

>> For years I've had discussions in comp.lang.c about things that C should
>> or should not have.

> Bart, don't be naive. The C language isn't going to "acquire a slick new
> enhancement" based on a few emails on compl.lang.c. C is an ISO-standard.
> Stability of the language,

C is a supposedly ultra-portable and apparently simple language. But
take an application like CPython - you can't just grab the nearest C
compiler and build it. You need to blindly run tens of thousands of
lines of scripts and assorted utilities, and compile with /gcc/, and
hope it works. And that's in Linux; on Windows it's different yet again.

And take C compilers such as gcc and MSVC - they're monsters (how long
would it take either of them to build itself? Now see below.)

The language and the way it's used have a few problems - why shouldn't
someone talk about them?

the fact that you have a known set of
> functionality, is precisely why it was made a standard in the first place:
> to discourage the sort of "wouldn't it be cool if..." pile up of features
> and bloat and ever-changing language specs.

Most of the enhancements I talked about were trivial. The language is
unlikely to change because of me but it would be nice for someone to
acknowledge them rather than defend one of C's crazy quirks or lack of a
feature to the death.

(I use my own implementation language in place of C, which fixes most of
those annoyances. Yesterday I was able to compile it entirely from
scratch in 0.016 seconds. And I haven't misplaced a decimal point!
More info: http://pastebin.com/yFKzs2eF)

> You are *incredibly* privileged to do all your work on your own custom
> programming languages,

These days anyone (any coder) can do that if they wish. Apparently most
people don't. I don't blame them.

> The size of Python isn't important to *you* on your fancy PC with entire
> gigabytes of hard drive, but to people interested in running Python on
> embedded hardware and micro-computers, every kilobyte counts.

The subject is about a feature that was available on any 1980s
microcomputer with memory measured in KB.

Anyway I know about small systems, and the ones I create are pretty
small (they will still fit on a floppy disk), but they will no longer
run on tiny systems. But I'd like to see Python running on a 64KB system
(Micropython doesn't count!).

>> I think this came up when someone wanted to switch from Visual Basic to
>> Python. The above is not a very sophisticated approach but it is very
>> simple and intuitive.
>
> Intuitive to whom? To me, it just looks weird.

'read a,b,c' is weird and unintuitive compared with its counterpart
'print a,b,c'. OK....

BTW what does reading three integers from the user look like in Python?

--
Bartc

bream...@gmail.com

unread,
Oct 29, 2016, 9:50:21 AM10/29/16
to
On Tuesday, October 25, 2016 at 11:02:47 AM UTC+1, BartC wrote:
> On 25/10/2016 07:39, Steven D'Aprano wrote:
>
> >> I gather that non-blocking keyboard input functions aren't the easiest thing
> >> to implement. They seem to depend on the operating system. Still, ease of
> >> use is a primary goal of Python, and the need for this feature must be
> >> common.
> >
> >
> > Not really. I think that lots of people think they need it, but once they write
> > a little utility, they often realise that it's not that useful.
>
> > If you (generic you, not you specifically) are telling the user "press any key
> > to continue", then you probably shouldn't. *Any* key may not do anything. E.g.
> > if the user hits the Shift key. A much better interface is to specify a
> > specific key, and ignore anything else... in which case, why not specify the
> > Enter key?
> >
> > raw_input('Press the Enter key to continue... ')
>
> Which doesn't work on Python 3. So even here, making it easy by using
> line-input, it's not so straightforward.
>

Just get this http://pythonhosted.org/six/ or similar.

Steve D'Aprano

unread,
Oct 29, 2016, 10:19:31 AM10/29/16
to
On Sat, 29 Oct 2016 10:53 pm, BartC wrote:

> On 29/10/2016 02:04, Steve D'Aprano wrote:
>> On Fri, 28 Oct 2016 05:09 am, BartC wrote:
>
>>> For years I've had discussions in comp.lang.c about things that C should
>>> or should not have.
>
>> Bart, don't be naive. The C language isn't going to "acquire a slick new
>> enhancement" based on a few emails on compl.lang.c. C is an ISO-standard.
>> Stability of the language,
>
> C is a supposedly ultra-portable and apparently simple language.

I'm not sure if C *ever* was simple, but it certainly hasn't been simple for
the last quarter of a century.

The most recent version of the standard has a draft of 701 pages:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

The draft for the previous standard, C99, was 552 pages:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

See also:

http://www.open-std.org/jtc1/sc22/wg14/www/standards
http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents


Here's a draft of ANSI C (C89):

http://flash-gordon.me.uk/ansi.c.txt

My browser formats that to 290 pages. So even in 1989, C was significantly
complex.



[...]
> The language and the way it's used have a few problems - why shouldn't
> someone talk about them?

Nobody is stopping you from discussing C's problems in the appropriate
forum. But unlike you and your hand-made compilers, with a user-base of
exactly 1 user (you), there are dozens of implementations of C, with tens
of thousands of users or more, and an ISO standard defining what is and
isn't C.


> the fact that you have a known set of
>> functionality, is precisely why it was made a standard in the first
>> place: to discourage the sort of "wouldn't it be cool if..." pile up of
>> features and bloat and ever-changing language specs.
>
> Most of the enhancements I talked about were trivial. The language is
> unlikely to change because of me but it would be nice for someone to
> acknowledge them rather than defend one of C's crazy quirks or lack of a
> feature to the death.

You won't get any defence of C's crazy quirks from me.

[...]
> But I'd like to see Python running on a 64KB system
> (Micropython doesn't count!).

Hmmm. So tell me... how do you expect Python to run on tiny systems by
*adding* new features?

Regardless of how "small" this feature is, it is not negative size. The
implementation is at least 1 byte. The documentation is at least 1 byte.
The tests are at least 1 byte. If you think Python is too big now, then
adding this feature will make it at least 3 bytes bigger.


>>> I think this came up when someone wanted to switch from Visual Basic to
>>> Python. The above is not a very sophisticated approach but it is very
>>> simple and intuitive.
>>
>> Intuitive to whom? To me, it just looks weird.
>
> 'read a,b,c' is weird and unintuitive compared with its counterpart
> 'print a,b,c'. OK....

print as a statement was always an anomaly, and yes, it got pretty weird:

print >>sys.stderr, spam, eggs

So much nicer now that it is a function that takes proper keyword arguments.

In any case, I wasn't specifically talking about

read a, b, c

Yes, it is a bit (actually a lot) unusual to assign a value to a variable by
way of a statement other than assignment, it is not unprecedented in
Python. We have at least three other binding statements:

import name

for name in ...

del name


even though one of them is actually an *unbinding* statement. What I said
looked weird was your syntax:

read a:"h", b:"r", c:"s"


If you're going to introduce special syntax for types, why make the types
strings rather than symbols?


> BTW what does reading three integers from the user look like in Python?

for i in range(3):
n = int(input(""))


You want a prompt? Change the empty string to your prompt.

You want to assign to three different variables? Unroll the loop:

n = int(input(""))
p = int(input(""))
q = int(input(""))


If the user types something that isn't an integer, you want to try again?
Write a loop. If you're sensible, of course you will put it into a helper
function:


_SENTINEL = object()

def read_int_with_all_the_trimmings(
prompt1='Enter an int: ',
prompt2='Invalid value for an int; please try again: ',
prompt3='Value out of range; please try again: ',
max_times=2**31,
low=None,
high=None,
default=_SENTINEL):
msg = prompt1
for attempt in range(max_times):
s = input(msg)
try:
n = int(s)
except ValueError:
msg = prompt2
else:
out_of_range = (low is not None and n < low) or (
high is not None and n > high)
if out_of_range:
msg = prompt3
else:
return n
if default is _SENTINEL:
raise ValueError('not a valid int')
return default




Does your `read` statement do all that? Why not?

BartC

unread,
Oct 29, 2016, 10:32:32 AM10/29/16
to
On 29/10/2016 14:51, Dennis Lee Bieber wrote:
> On Sat, 29 Oct 2016 12:53:35 +0100, BartC <b...@freeuk.com> declaimed the
> following:
>
>>
>> BTW what does reading three integers from the user look like in Python?
>
> On one line, or on three lines?
>
> (Python 2.7)
>
> ln = raw_input("Enter three integers separated by spaces: ")
> ints = []
> for i, wd in enumerate(ln.split()):
> try:
> anInt = int(wd)
> except: #yes, I know -- the horrible bare except clause
> print ("***** item %s: '%s' could not be converted to integer"
> % (i, wd) )
> anInt = None
> ints.append(anInt)

Yes, that's the sort of thing I was expecting, that's why I asked.

I still think a beginner would much prefer something along the lines of
'readln a,b,c' (and I still think that's more intuitive).

(The first programming exercises I ever did involved typing in integers
from the user, and sorting them or working out if they made a triangle
or whatever.

But in Python someone would first need to master for-loops, enumeration,
string-processing, numeric conversion, exceptions and, your second
example, functions. That's quite a steep learning curve! (And that
second example starts to involve re-inventing things.)

(BTW the functionality of my 'readln a,b,c' differs from the above.
Separators can be anything reasonable. When eol is encountered, it will
read zeros. And errors are not handled: any non-numeric will yield zero.

When reading name, file and string items rather than integers, the split
method doesn't deal with embedded quotes. Probably there are bigger guns
you can bring out to deal with more elaborate input, but it starts to
get further away from beginner level.)

--
Bartc


Chris Angelico

unread,
Oct 29, 2016, 10:53:36 AM10/29/16
to
On Sun, Oct 30, 2016 at 1:32 AM, BartC <b...@freeuk.com> wrote:
> BTW the functionality of my 'readln a,b,c' differs from the above.
> Separators can be anything reasonable. When eol is encountered, it will read
> zeros. And errors are not handled: any non-numeric will yield zero.

People will disagree as to what is "correct behaviour" in that kind of
situation. If someone disagrees with Steve's function, s/he can write
a different one. If someone disagrees with your language primitive....
s/he can write a different language?

ChrisA

Steve D'Aprano

unread,
Oct 29, 2016, 11:24:26 AM10/29/16
to
On Sun, 30 Oct 2016 01:32 am, BartC wrote:

> (BTW the functionality of my 'readln a,b,c' differs from the above.
> Separators can be anything reasonable. When eol is encountered, it will
> read zeros. And errors are not handled: any non-numeric will yield zero.

Ah, in other words it is a toy, utterly unsuitable for serious use by anyone
who cares about data validity and error checking, only suitable for
teaching bad habits to beginners.

BartC

unread,
Oct 29, 2016, 11:25:07 AM10/29/16
to
On 29/10/2016 15:19, Steve D'Aprano wrote:
> On Sat, 29 Oct 2016 10:53 pm, BartC wrote:

>> But I'd like to see Python running on a 64KB system
>> (Micropython doesn't count!).
>
> Hmmm. So tell me... how do you expect Python to run on tiny systems by
> *adding* new features?
>
> Regardless of how "small" this feature is, it is not negative size. The
> implementation is at least 1 byte. The documentation is at least 1 byte.
> The tests are at least 1 byte. If you think Python is too big now, then
> adding this feature will make it at least 3 bytes bigger.

The /effective/ size could well be negative! If someone really needs the
feature they might need to drag in 'curses' or require 'tkinter',
substantial add-ons even though they only need one minor feature.

> print as a statement was always an anomaly, and yes, it got pretty weird:
>
> print >>sys.stderr, spam, eggs

> So much nicer now that it is a function that takes proper keyword arguments.

I guess ">>" is what I used "#" or "@" for. But what does it look like
in function form?

Functions are great for adding general-purpose utility but their syntax
is limited; sometimes dedicated syntax is better for things you use all
the time.

> What I said
> looked weird was your syntax:
>
> read a:"h", b:"r", c:"s"
>
>
> If you're going to introduce special syntax for types, why make the types
> strings rather than symbols?

(I can't remember where that came from. The colon syntax I think was
from Pascal. I used strings for the Print counterpart as there can be
other stuff in there: x:"z8hs'" might display x as "0001'E800".

Read formats could have been single unquoted characters I suppose (they
were once). But a string means the format can be dynamic: read a:fmt,b:fmt.

But this is a detail. The main thing is trivially just listing the
things you want to read in a similar manner to print.)

>> BTW what does reading three integers from the user look like in Python?
>
> for i in range(3):
> n = int(input(""))

OK, one per line. Just so each input line corresponds to exactly one
integer! (I can do this too but I write it as:

n := strtoval(sreadln()) # int default
x := strtoval(sreadln(),"r") # floating point ('real') )

> You want a prompt? Change the empty string to your prompt.
>
> You want to assign to three different variables? Unroll the loop:
>
> n = int(input(""))
> p = int(input(""))
> q = int(input(""))

>
> If the user types something that isn't an integer, you want to try again?

The idea of read and print statements, in my languages at least, are for
simple or throwaway programs, or when dealing with known file formats:

r := "r"
readln @file, x:r, y:r, z:r

It's not /meant/ to be sophisticated. Just convenient.
I don't understand your point. No, it doesn't, but neither does Python
(it doesn't have 'read' for a start). You've had to write it; I can too.
And that example still reads one number per line!

Suppose you have to read a ppm file which might start like this:

P6
600 800
255

I can read this using 'read': (checking and comment-skipping code omitted):

readln @f, sig:"s"
readln @f, width, height
readln @f, maxpix

It doesn't need anything fancy and you don't want to bother with parsing
the input lines and converting text to numbers.

--
Bartc

Christian Gollwitzer

unread,
Oct 29, 2016, 11:27:06 AM10/29/16
to
Am 29.10.16 um 16:32 schrieb BartC:
> I still think a beginner would much prefer something along the lines of
> 'readln a,b,c' (and I still think that's more intuitive).
>
> (The first programming exercises I ever did involved typing in integers
> from the user, and sorting them or working out if they made a triangle
> or whatever.

Yes, and that's exactly why they learn to produce such horrible
interfaces which do not work for a serious program. Instead, teach them
how to use the *environment* for I/O. That is, as a beginner put your
function into a file, e.g.

def is_triangle(a, b, c):
if abs(a)+abs(b) > abs(c):
print "Triangle!"
else:
print "Not a triangle"

..and then use IPython:

%run triangle.py
>>> is_triangle(1,1.7, 2)
Triangle!
>>> is_triangle(1,1.7, 8)
Not a triangle
>>>

(I know the prog is incomplete, but that's not the point)

This way you can concentrate on the algorithm and leave the I/O thing to
python. Due to the built-in readline, you can recall previous arguments,
edit them when you make mistakes, save the result (if there were any),
.... much more than your readln function can accomplish.

Christian
It is loading more messages.
0 new messages