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

Terry Reedy tjreedy at udel.edu
Wed Oct 26 22:15:24 EDT 2016


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




More information about the Python-list mailing list