[Tutor] Event loop logic question

Dennis Lee Bieber wlfraed at ix.netcom.com
Sat Jun 25 22:55:14 EDT 2022


On Sun, 26 Jun 2022 10:06:25 +1000, Phil <phillor9 at gmail.com> declaimed the
following:

	WARNING: LONG HARANGUE FOLLOWS

>
>I was looking for an easy way to repeatedly read the keyboard and 
>pygamezero fills the bill. The problem that I initially had was that the 
>update function is called many times per second and sending control 
>commands from there caused the receiving hardware to be overwhelmed and 
>then to crash. The UI is a 20 * 20 square and servers no use at all, 
>it's just a requirement as far as I can tell, and so does not need 
>updating. All I need is to read the arrow keys and to be able to quit 
>the programme.
>

	In most GUI frameworks -- update would be called whenever the framework
has processed an event (some may have an ability to process a couple of
events and collect changes for one update call). Pygame Zero apparently
uses update() to render changes to the GUI buffer, and a separate draw()
operation to copy the buffer to the screen.

	There is no inherent means of rate-limiting a GUI framework. YOU will
have to write code to do rate limiting either within the event handlers, or
in the update operation. That likely means you need to track system elapsed
time for each event, issue an actual update to your device only if enough
elapsed time has passed and there has been no change in event type; OR you
issue a command when the event type changes.

	Looking for repeated key events can be troublesome. The OS handles the
keyboard repeat rate, and sends them (events) to whatever
application/framework is asking for them. Most likely, that means you might
receive a keydown/keyup event pair for each repetition. The only way to
confirm is to have a test application log (probably to a file, as it can
buffer entries rather than slowly updating a screen) each event it sees.

	Don't know if it applies but...
https://www.mattlayman.com/blog/2019/teach-kid-code-pygame-zero/
"""
The common pieces that you must handle yourself in Pygame are pre-wired in
Pygame Zero. This dramatically lowers the barrier to entry, at the cost of
flexibility. It’s absolutely the right trade-off for teaching.
"""
... could mean stuff you are trying to do is not really available.

	However, from the documentation, the best option for rate limiting is
to use	clock.schedule_interval()	configured to call a function that
issues commands to the end device, it will use an interval that will not
overload the device (you may have to experiment -- 1.0/20.0 would produce
20 commands per second).

	You will NOT issue commands from .update() or .draw() (though you might
use them to have that "unused" GUI window produce a heartbeat display).

	Your .on_key_down() and .on_key_up() callbacks just set a state flag
(I'm assuming more than binary state -- EXIT, IDLE, FORWARD, whatever else.
But you do need to verify that holding a key down doesn't result in
multiple down/up calls as the system repeats the key. If it does, you will
have more difficulties since the key handler state could go from, say
FORWARD to IDLE before the scheduler checks for command sending.

	I'm tempted to suggest that you ignore key_up events. You set the state
for the depressed key, and have the scheduler clear the state to "IDLE"
(but don't issue the idle command on this invocation). If no key has been
pressed since the scheduler cleared it, the next scheduled time will see
the IDLE and issue the proper command. Otherwise, a repeating key will be
another key_down event on return from the scheduler, and the event handler
will just reset the state to the proper value for that key.


	If the "GUI" is not really being used, why even invoke a GUI framework.
Just run a console application.

	On Windows, there is the msvcrt module in the standard library. It has
functions for 
"""
msvcrt.kbhit()
    Return True if a keypress is waiting to be read.

msvcrt.getch()
    Read a keypress and return the resulting character as a byte string.
Nothing is echoed to the console. This call will block if a keypress is not
already available, but will not wait for Enter to be pressed. If the
pressed key was a special function key, this will return '\000' or '\xe0';
the next call will return the keycode. The Control-C keypress cannot be
read with this function.
"""

	For Linux systems, there are a few modules to terminal IO control (but
understanding what you'd need to get characters as entered. Might be easier
to create a curses application (which should be available for Linux,
Windows ports are more problematic).
"""
curses.cbreak()
    Enter cbreak mode. In cbreak mode (sometimes called “rare” mode) normal
tty line buffering is turned off and characters are available to be read
one by one. However, unlike raw mode, special characters (interrupt, quit,
suspend, and flow control) retain their effects on the tty driver and
calling program. Calling first raw() then cbreak() leaves the terminal in
cbreak mode.
"""
Note that doesn't mention key down/key up.
"""
curses.noecho()
    Leave echo mode. Echoing of input characters is turned off.
"""
"""
window.getch([y, x])
    Get a character. Note that the integer returned does not have to be in
ASCII range: function keys, keypad keys and so on are represented by
numbers higher than 255. In no-delay mode, return -1 if there is no input,
otherwise wait until a key is pressed.


window.getkey([y, x])
    Get a character, returning a string instead of an integer, as getch()
does. Function keys, keypad keys and other special keys return a multibyte
string containing the key name. In no-delay mode, raise an exception if
there is no input.
"""
Don't see an equivalent for .kbhit()


-- 
	Wulfraed                 Dennis Lee Bieber         AF6VN
	wlfraed at ix.netcom.com    http://wlfraed.microdiversity.freeddns.org/



More information about the Tutor mailing list