Re: Does one have to use curses to read single characters from keyboard?

2022-12-13 Thread Alan Gauld
On 12/12/2022 17:45, Alan Gauld wrote:

Absolutely nothing apparently!

But in practce I did pen some esponses to Davids post. However
this list seems to strip out what I've written, its happened
a few times now. Not every time but enough that I rarely post
here.

But I'll try once more...

> On 11/12/2022 21:07, dn wrote:
>> On 11/12/2022 23.09, Chris Green wrote:
>>> Is the only way to read single characters from the keyboard to use
>>> curses.cbreak() or curses.raw()?

>> You may like to re-ask this question over on the Python-Tutor list. The 
>> ListAdmin over there (literally) wrote the book on Python+curses...

Thanks for the plug David, but...

While my book is, I think, the only one specifically for curses with
Python, it's hardly a definitive tome on the subject, rather a
beginner's tutorial. An expanded HowTo if you like..

>> Did such research include the keyboard module?
>> https://pypi.org/project/keyboard/

There are several such modules, including a good one by Fred Lundh.
They are cross platform and probably the best solution for the
OP if he doesn't mind using a third party module. I think Fred's
was called terminal? But its been a while I normally just use curses
for anything terminal related.

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-12 Thread Grant Edwards
On 2022-12-11, Chris Green  wrote:

> Is the only way to read single characters from the keyboard to use
> curses.cbreak() or curses.raw()?

No.

> If so how do I then read characters,

Use a termios.tcsetattr() to put fd 0 into raw mode and then use
os.read().

Recent versions of Python include a "tty" module that has conveniece
functions to handle that:

--
Grant





-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-12 Thread Alan Gauld
On 11/12/2022 21:07, dn wrote:
> On 11/12/2022 23.09, Chris Green wrote:
>> Is the only way to read single characters from the keyboard to use
>> curses.cbreak() or curses.raw()?  If so how do I then read characters,
>> it's not at all obvious from the curses documentation as that seems to
>> think I'm using a GUI in some shape or form.
>>
>> All I actually want to do is get 'Y' or 'N' answers to questions on
>> the command line.
>>
>> Searching for ways to do this produces what seem to me rather clumsy
>> ways of doing it.
> 
> You may like to re-ask this question over on the Python-Tutor list. The 
> ListAdmin over there (literally) wrote the book on Python+curses...
> 
> 
> Did such research include the keyboard module?
> https://pypi.org/project/keyboard/
> 
> This project includes an (Enter-free) "hot-key" feature which firstly 
> detects the specific key or key-combination, and then calls an action 
> if/when True.
> (amongst other functionality)
> 
> Quick read tutorial: 
> https://www.thepythoncode.com/article/control-keyboard-python
> 
> Disclaimer: have had it on my 'radar', but never actually employed.
> (if you have considered, will be interested to hear conclusions...)

-- 
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-12 Thread Chris Green
Barry Scott  wrote:
> 
> 
> > On 11 Dec 2022, at 18:50, Chris Green  wrote:
> > 
> > My solution in the end was copied from one I found that was much
> > simpler and straightforward than most.  I meant to post this earlier
> > but it got lost somewhere:-
> > 
> >import sys, termios, tty
> >#
> >#
> ># Read a single character from teminal, specifically for 'Y/N' 
> >#
> >fdInput = sys.stdin.fileno()
> >termAttr = termios.tcgetattr(0)
> >#
> >#
> ># Get a single character, setcbreak rather than setraw meands CTRL/C
> >etc. still work
> >#
> >def getch():
> >sys.stdout.flush()
> >tty.setcbreak(fdInput)
> >ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)
> 
> Will not work for uncode code points above 255.
> 
> This is what happened when I typed € key:
> 
> :>>> a.getch()
> Traceback (most recent call last):
>   File "", line 1, in 
>   File "/private/var/folders/ll/08dwwqkx6v9bcd15sh06x14wgn/T/a.py", line 
> 15, in getch
> ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)
> UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 0: 
> unexpected end of data
> 
Since it's just for me to use the above doesn't worry me! :-)  I'd
have to try quite hard to enter a multi-byte character from my
keyboard so it's very unlikely to happen by mistake.

-- 
Chris Green
·
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-12 Thread Chris Green
Stefan Ram  wrote:
> Chris Green  writes:
> >import sys, termios, tty
> 
>   There might be some versions of Python and the Microsoft®
>   Windows operating system where "termios" is not available.
> 

Ah, I did originally say that this was a Unix/Linux only solution but
that was in my first response that got lost somewhere.

-- 
Chris Green
·
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Cameron Simpson

On 11Dec2022 22:22, Barry Scott  wrote:
   # Get a single character, setcbreak rather than setraw meands 
   CTRL/C

   etc. still work
   #
   def getch():
   sys.stdout.flush()
   tty.setcbreak(fdInput)
   ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)


Will not work for uncode code points above 255.


Aye. But one could write a little loop to collect bytes until a complete 
character was received. A little experiment:


>>> try: bytes((0xf0,)).decode('utf8')
... except UnicodeDecodeError as e:
...   e2=e
...
>>> e2
UnicodeDecodeError('utf-8', b'\xf0', 0, 1, 'unexpected end of data')
>>> e2.reason
'unexpected end of data'

Keep collecting while you get `UnicodeDecodeError`s with a `.reason` of 
'unexpected end of data'. Can be encoding agnostic (obviously you need 
to _choose_ an encoding, it is needn't be utf-8).


(For the OP: `UnicodeDecodeError` doesn't necessarily mean you're 
decoding Unicode data, you're decoding _into_ a Python string which is a 
Unicode string.)


Cheers,
Cameron Simpson 
--
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Chris Angelico
On Mon, 12 Dec 2022 at 09:24, Barry Scott  wrote:
> You would need to have a loop that collected all the utf-8 bytes of a single 
> code point.
> You can to look at the first byte of know if the utf-8 is 1, 2, 3 or 4 bytes 
> for a code point.

And cope with escape sequences too - if you press an arrow key, for
instance, you'll get a multi-character string to signal that.

This is why it's probably easier to let someone else do the work.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Barry Scott


> On 11 Dec 2022, at 18:50, Chris Green  wrote:
> 
> My solution in the end was copied from one I found that was much
> simpler and straightforward than most.  I meant to post this earlier
> but it got lost somewhere:-
> 
>import sys, termios, tty
>#
>#
># Read a single character from teminal, specifically for 'Y/N' 
>#
>fdInput = sys.stdin.fileno()
>termAttr = termios.tcgetattr(0)
>#
>#
># Get a single character, setcbreak rather than setraw meands CTRL/C
>etc. still work
>#
>def getch():
>sys.stdout.flush()
>tty.setcbreak(fdInput)
>ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)

Will not work for uncode code points above 255.

This is what happened when I typed € key:

:>>> a.getch()
Traceback (most recent call last):
  File "", line 1, in 
  File "/private/var/folders/ll/08dwwqkx6v9bcd15sh06x14wgn/T/a.py", line 
15, in getch
ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 0: 
unexpected end of data

You would need to have a loop that collected all the utf-8 bytes of a single 
code point.
You can to look at the first byte of know if the utf-8 is 1, 2, 3 or 4 bytes 
for a code point.

Barry

>termios.tcsetattr(fdInput, termios.TCSAFLUSH, termAttr)
>sys.stdout.write(ch)
>return ch
>#
>#
># Get a y or n answer, ignore other characters
>#
>def getyn():
>ch = 'x'
>while ch != 'y' and ch != 'n':
>ch = getch().lower()
>return ch
> 
> So getyn() reads a y or an n, ignores anything else and doesn't wait
> for a return key.  Keyboard input operation is restored to normal
> after doing this. Using tty.setcbreak() rather than tty.setraw() means
> that CTRL/C etc. still work if things go really wrong.

> 
> 
> -- 
> Chris Green
> ·
> -- 
> https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread dn

On 11/12/2022 23.09, Chris Green wrote:

Is the only way to read single characters from the keyboard to use
curses.cbreak() or curses.raw()?  If so how do I then read characters,
it's not at all obvious from the curses documentation as that seems to
think I'm using a GUI in some shape or form.

All I actually want to do is get 'Y' or 'N' answers to questions on
the command line.

Searching for ways to do this produces what seem to me rather clumsy
ways of doing it.


You may like to re-ask this question over on the Python-Tutor list. The 
ListAdmin over there (literally) wrote the book on Python+curses...



Did such research include the keyboard module?
https://pypi.org/project/keyboard/

This project includes an (Enter-free) "hot-key" feature which firstly 
detects the specific key or key-combination, and then calls an action 
if/when True.

(amongst other functionality)

Quick read tutorial: 
https://www.thepythoncode.com/article/control-keyboard-python


Disclaimer: have had it on my 'radar', but never actually employed.
(if you have considered, will be interested to hear conclusions...)
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Chris Green
My solution in the end was copied from one I found that was much
simpler and straightforward than most.  I meant to post this earlier
but it got lost somewhere:-

import sys, termios, tty
#
#
# Read a single character from teminal, specifically for 'Y/N' 
#
fdInput = sys.stdin.fileno()
termAttr = termios.tcgetattr(0)
#
#
# Get a single character, setcbreak rather than setraw meands CTRL/C
etc. still work
#
def getch():
sys.stdout.flush()
tty.setcbreak(fdInput)
ch = sys.stdin.buffer.raw.read(1).decode(sys.stdin.encoding)
termios.tcsetattr(fdInput, termios.TCSAFLUSH, termAttr)
sys.stdout.write(ch)
return ch
#
#
# Get a y or n answer, ignore other characters
#
def getyn():
ch = 'x'
while ch != 'y' and ch != 'n':
ch = getch().lower()
return ch

So getyn() reads a y or an n, ignores anything else and doesn't wait
for a return key.  Keyboard input operation is restored to normal
after doing this. Using tty.setcbreak() rather than tty.setraw() means
that CTRL/C etc. still work if things go really wrong.


-- 
Chris Green
·
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Antoon Pardon




Op 11/12/2022 om 12:32 schreef Stefan Ram:

r...@zedat.fu-berlin.de (Stefan Ram) writes:

Curses is not portable IIRC. A more portable means would
be to use tkinter with the "bind" function to bind keys.

import tkinter

text = tkinter.Text()
text.pack()
text.bind\
( "",
   lambda event:
   text.insert
   ( tkinter.END, "Y\nFormatting drive C:\n...\n" )or "break" )
text.insert( tkinter.END, "Format drive C:?\n" )
text.focus()

tkinter.mainloop()

   Not allowing users to edit their keypresses before confirming
   them with [Return]. What could possibly go wrong?


Nothing that can't go wrong otherwise. It is my experience that
when a [Return] is needed, people just type in a two key combination.
They don't type one key, then check, then type [Return].

So in practice the same things go wrong, either way.

--
Antoon Pardon.
--
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Chris Nyland
You should try the input function. I use it all the time. It does require
the user to hit enter but that is pretty typical of that kind of interface.
So I would write a loop like

while True:
   answer = input("Please answer the question (y/n):")
  if answer == 'y':
break

Chris

On Sun, Dec 11, 2022 at 11:03 AM Stefan Ram  wrote:

> r...@zedat.fu-berlin.de (Stefan Ram) writes:
> >import tkinter
>
>   This two-liner allows to answer with just one keypress ([Y]/[N]) here.
>
> import tkinter.messagebox
> tkinter.messagebox.askyesno( "Question", "Format harddisk?" )
>
>
> --
> https://mail.python.org/mailman/listinfo/python-list
>
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Oscar Benjamin
On Sun, 11 Dec 2022 at 15:55, Chris Green  wrote:
>
> Is the only way to read single characters from the keyboard to use
> curses.cbreak() or curses.raw()?  If so how do I then read characters,
> it's not at all obvious from the curses documentation as that seems to
> think I'm using a GUI in some shape or form.
>
> All I actually want to do is get 'Y' or 'N' answers to questions on
> the command line.
>
> Searching for ways to do this produces what seem to me rather clumsy
> ways of doing it.

What you are asking for is known as getch. On Windows Python's msvcrt
module provides precisely this function. There are ways to do it on
non-Windows platforms but nothing as simple as the getch function is
in the stdlib. Some modules and recipes are available which I guess it
what you've already seen:

https://pypi.org/project/getch/
https://github.com/joeyespo/py-getch
https://stackoverflow.com/questions/510357/how-to-read-a-single-character-from-the-user

This seems to be the most well maintained option:
https://pypi.org/project/readchar/

I've often thought that getch was a good candidate for the stdlib.
There are plenty of recipes around but it would ideally just be
available as a cross platform function. Using curses would have been
overkill in any of my use cases where I really just wanted getch to
make a more efficient interface for a terminal program having some
limited interactivity. Actually slightly more than getch is readchar's
readkey which also works for pressing non-character keys. There were
times in the past where I might have used that if I'd known about it.

--
Oscar
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread Chris Green
Stefan Ram  wrote:
> Chris Green  writes:
> >Is the only way to read single characters from the keyboard to use
> >curses.cbreak() or curses.raw()?  If so how do I then read characters,
> 
>   It seems that you want to detect keypresses and not read
>   characters from a line-buffered console with editing
>   features.
> 
>   Curses is not portable IIRC. A more portable means would 
>   be to use tkinter with the "bind" function to bind keys.
> 
> >All I actually want to do is get 'Y' or 'N' answers to questions on
> >the command line.
> 
>   answer = input( 'Format drive C: (Y/N)?' )
> 
... and therein lies the fundamental problem, you have to type Y or N
followed by Return.  See my own follow-up though.

-- 
Chris Green
·
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Does one have to use curses to read single characters from keyboard?

2022-12-11 Thread DFS

On 12/11/2022 5:09 AM, Chris Green wrote:

Is the only way to read single characters from the keyboard to use
curses.cbreak() or curses.raw()?  If so how do I then read characters,
it's not at all obvious from the curses documentation as that seems to
think I'm using a GUI in some shape or form.

All I actually want to do is get 'Y' or 'N' answers to questions on
the command line.

Searching for ways to do this produces what seem to me rather clumsy
ways of doing it.



resp = 'x'
while resp.lower() not in 'yn':
resp = input("Did you say Y or did you say N?: ")




--
https://mail.python.org/mailman/listinfo/python-list