I'm coding a program that, at its most basic level, involves moving a square across a tkinter canvas with WASD. At first, I had problems with diagonal movements, and stopping properly, but those issues have since been resolved. My current problem comes from a "slow mode" that allows for slower, more precise movement.
By pressing left shift, movement speed is reduced, and pressing it again returns speed to normal. I've gotten the implementation to the point where it works perfectly (slow mode key unbinds itself and uses a keyrelease function to rebind, suppressing auto-repeat). However, should one choose to hold down shift anyway, the directional keys lock up. Not just that, but the keyrelease events that stop movement also cease to function, causing the square to continue moving on its own if shift is held when the directional key is released.
Since shift unbinds itself, I don't know why it is blocking everything else. Perhaps it has something to do with waiting for the keyrelease, but directional movements also wait for keyrelease events, and diagonal moves with multiple keys are still possible. And such, I'm unsure as to why slow mode is causing interference, when the directional buttons do not.
A basic version of the program is reproduced below:
import tkinter as tk
from time import sleep
from _thread import start_new_thread
from threading import Event
class Levels(tk.Frame):
def __init__(self):
self.root = tk.Tk()
tk.Frame.__init__(self)
self.grid()
self.master.resizable(False, False)
self.master.title("WASD moves, shift toggles slow")
self.master.geometry("370x270")
self.field = tk.Canvas(self, bg='azure')
self.field.grid(sticky='news')
self.player = self.field.create_rectangle(30, 30, 50, 50, fill='green')
self.x_velocity = self.y_velocity = 0
self.speed_modifier = 1
self.key_binds = {'UP': 'w', 'DOWN': 's', 'LEFT': 'a', 'RIGHT': 'd', 'SLOWMODE': 'Shift_L'}
self.bind_controls()
start_new_thread(self.game_loop, ())
def game_loop(self):
while True:
self.field.move(self.player, self.x_velocity*self.speed_modifier, self.y_velocity*self.speed_modifier)
sleep(0.05)
def queue_move(self, x_move=0, y_move=0):
if x_move:
self.x_velocity = x_move
else: # y_move
self.y_velocity = y_move
def queue_stop(self, x_stop=-9, y_stop=-9):
if x_stop == self.x_velocity:
self.x_velocity = 0
elif y_stop == self.y_velocity:
self.y_velocity = 0
def slow_mode_toggle(self, _=None):
self.root.unbind(f"<{self.key_binds['SLOWMODE']}>")
self.speed_modifier = 0.5 if self.speed_modifier == 1 else 1
self.root.bind(f"<KeyRelease-{self.key_binds['SLOWMODE']}>", self.slow_mode_rebind)
def slow_mode_rebind(self, _=None):
self.root.unbind(f"<KeyRelease-{self.key_binds['SLOWMODE']}>")
self.root.bind(f"<{self.key_binds['SLOWMODE']}>", self.slow_mode_toggle)
def bind_controls(self):
self.root.bind(f"<{self.key_binds['UP']}>", lambda _: self.queue_move(y_move=-4))
self.root.bind(f"<{self.key_binds['DOWN']}>", lambda _: self.queue_move(y_move=4))
self.root.bind(f"<{self.key_binds['LEFT']}>", lambda _: self.queue_move(x_move=-4))
self.root.bind(f"<{self.key_binds['RIGHT']}>", lambda _: self.queue_move(x_move=4))
self.root.bind(f"<KeyRelease-{self.key_binds['UP']}>", lambda _: self.queue_stop(y_stop=-4))
self.root.bind(f"<KeyRelease-{self.key_binds['DOWN']}>", lambda _: self.queue_stop(y_stop=4))
self.root.bind(f"<KeyRelease-{self.key_binds['LEFT']}>", lambda _: self.queue_stop(x_stop=-4))
self.root.bind(f"<KeyRelease-{self.key_binds['RIGHT']}>", lambda _: self.queue_stop(x_stop=4))
self.root.bind(f"<{self.key_binds['SLOWMODE']}>", self.slow_mode_toggle)
if __name__ == "__main__":
Levels().mainloop()
Update: I tested this with a different keypress -> keyrelease event set that didn't directly affect x_velocity or y_velocity, and there was no issue. I then tested it by binding slow mode to a different key, and also no issue. I then tested it by holding shift when slow mode was bound to a different key, and the problematic behaviour returned. This also occurred for the right shift key. It seems that it is not the way the function was coded, but something inherent to the shift keys themselves that is causing the issue. Left shift is the most convenient key to use for this, but I can use another key if necessary. I would still like to know if there is any way to resolve the issue with shift, however.