import queue import threading import time import tkinter as tk from car import KITT import serial.tools.list_ports from pynput import keyboard if __name__ == "__main__": serial_selector = tk.Tk() serial_selector.title("Select serial port") ports = list(serial.tools.list_ports.comports()) length = len(ports) * 25 serial_selector.geometry(f"600x{length+50}") selected_port = tk.StringVar() for port in ports: tk.Radiobutton(serial_selector,text = f"{port.device}",variable=selected_port,value= port.device).pack() def select_port(): global selected_port selected_port = selected_port.get() serial_selector.destroy() button = tk.Button(serial_selector, text="Select serial port", command=select_port) button.pack() serial_selector.mainloop() car = KITT(f"{selected_port}") root = tk.Tk() root.title("Patatje Oorloog") root.geometry("800x600") speed_label = tk.Label(root, text=f"Speed {car.get_speed()}") speed_label.grid(row = 0, column = 0) speed_var = tk.StringVar() speed_entry = tk.Entry(root, textvariable=speed_var) speed_entry.grid(row = 0, column = 1) def speed_btn(): global car car.set_speed(speed_var.get()) speed_label.config(text = f"Speed {car.get_speed()}") speed_set_btn = tk.Button(root, text="Set Speed", command=speed_btn) speed_set_btn.grid(row = 0, column = 2) angle_label = tk.Label(root, text=f"Angle {car.get_angle()}") angle_label.grid(row = 1, column = 0) angle_var = tk.StringVar() angle_entry = tk.Entry(root, textvariable=angle_var) angle_entry.grid(row=1, column=1) def angle_btn(): global car car.set_angle(angle_var.get()) angle_label.config(text=f"Speed {car.get_angle()}") angle_set_btn = tk.Button(root, text="Set Angle", command=angle_btn) angle_set_btn.grid(row=1, column=2) beacon_label = tk.Label(root, text=f"Beacon {car.get_beacon_state()}") beacon_label.grid(row = 2, column = 0) def toggle_beacon_btn(): global car car.toggle_beacon() beacon_label.config(text = f"Beacon {car.get_beacon_state()}") beacon_toggle = tk.Button(root, text="Toggle Beacon", command=toggle_beacon_btn) beacon_toggle.grid(row = 2, column = 1) def close_btn_func(): car.stop_beacon() car.stop() try: car.close() except OSError: pass root.destroy() close_btn = tk.Button(root, text="Close", command=close_btn_func) close_btn.grid(row = 10,column = 0) # Thread-safe queue for passing keys from listener to Tkinter key_queue = queue.Queue() last_key = None def start_listener(): """Start pynput listener in a background thread.""" def on_press(key): # Put a string representation of the key into the queue global last_key try: key_queue.put(f"{key.char}") if True: #not key == last_key : if key.char == "w": car.set_speed(165) speed_label.config(text = f"Speed {car.get_speed()}") if key.char == "s": car.set_speed(140) speed_label.config(text=f"Speed {car.get_speed()}") if key.char == "a": car.set_angle(200) angle_label.config(text=f"Angle {car.get_angle()}") if key.char == "d": car.set_angle(100) angle_label.config(text=f"Angle {car.get_angle()}") #last_key = key except AttributeError: key_queue.put(str(key)) def on_release(key): # Stop listener if ESC is pressed if key == keyboard.Key.esc: return False try : if key.char == "w": car.set_speed(150) speed_label.config(text=f"Speed {car.get_speed()}") if key.char == "s": car.set_speed(150) speed_label.config(text=f"Speed {car.get_speed()}") if key.char == "a": car.set_angle(150) angle_label.config(text=f"Angle {car.get_angle()}") if key.char == "d": car.set_angle(150) angle_label.config(text=f"Angle {car.get_angle()}") except AttributeError: pass return None def run_listener(): with keyboard.Listener(on_press=on_press, on_release=on_release) as listener: listener.join() # Run listener in its own thread so it does not block Tkinter t = threading.Thread(target=run_listener, daemon=True) t.start() def poll_queue(): """Check the queue for new keys and update the label.""" try: while True: k = key_queue.get_nowait() current = label_var.get() label_var.set(f"Last key: {k}") except queue.Empty: pass # Schedule next poll root.after(10, poll_queue) label_var = tk.StringVar(value="Press any key (global). ESC stops listener.") label = tk.Label(root, textvariable=label_var, width=50) label.grid(row = 9,column = 0) start_button = tk.Button(root, text="Start listener", command=start_listener) start_button.grid(row = 9, column = 1) # Start polling the queue root.after(10, poll_queue) root.protocol("WM_DELETE_WINDOW", close_btn_func) root.mainloop()