Re: Does one have to use curses to read single characters from keyboard?
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?
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?
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?
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?
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?
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?
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?
> 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?
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?
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?
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?
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?
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?
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?
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