import tkinter as tk from tkinter import scrolledtext, Label, Button, Entry, StringVar, ttk, messagebox import datetime import queue class KeyPressView(tk.Frame): def __init__(self, master, controller): super().__init__(master) self.master = master self.controller = controller # Store reference to controller self.master.title("Jarvis Key Press Utility (AHK Integrated)") self.master.geometry("600x600") self.pack(fill=tk.BOTH, expand=True) self.grid_columnconfigure(0, weight=1) self.grid_columnconfigure(1, weight=1) self.grid_rowconfigure(0, weight=0) self.grid_rowconfigure(1, weight=0) self.grid_rowconfigure(2, weight=1) # --- Configuration Section --- self.config_frame = tk.LabelFrame(self, text="Configuration", padx=10, pady=10, font=('Inter', 10, 'bold')) self.config_frame.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky="ew") self.config_frame.grid_columnconfigure(1, weight=1) Label(self.config_frame, text="Key to Press:", font=('Inter', 10)).grid(row=0, column=0, padx=5, pady=5, sticky="w") self.key_to_press_var = StringVar(value="+") self.key_input_entry = Entry(self.config_frame, textvariable=self.key_to_press_var, width=20, font=('Inter', 10)) self.key_input_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew") Label(self.config_frame, text="(e.g., '+', 'a', 'enter', 'space', 'f5')", font=('Inter', 8), fg="#586e75").grid(row=1, column=1, padx=5, pady=0, sticky="nw") self.key_validation_label = Label(self.config_frame, text="Please enter a key to press.", font=('Inter', 8, 'bold'), fg="red") self.key_validation_label.grid(row=0, column=2, padx=5, pady=5, sticky="w") self.key_validation_label.grid_remove() Label(self.config_frame, text="Target Window:", font=('Inter', 10)).grid(row=2, column=0, padx=5, pady=5, sticky="w") self.target_window_title_var = StringVar(value="--- Select a Window ---") self.window_combobox = ttk.Combobox(self.config_frame, textvariable=self.target_window_title_var, state="readonly", font=('Inter', 10)) self.window_combobox.grid(row=2, column=1, padx=5, pady=5, sticky="ew") self.window_combobox.bind("<>", self.controller.on_window_selected) # Bind to controller directly self.refresh_button = Button(self.config_frame, text="Refresh Windows", command=self.controller.refresh_windows, font=('Inter', 9)) self.refresh_button.grid(row=2, column=2, padx=5, pady=5, sticky="ew") self.target_window_validation_label = Label(self.config_frame, text="Please select a target window.", font=('Inter', 8, 'bold'), fg="red") self.target_window_validation_label.grid(row=3, column=1, padx=5, pady=0, sticky="nw") self.target_window_validation_label.grid_remove() # --- Control Buttons Section --- self.button_frame = tk.Frame(self) self.button_frame.grid(row=1, column=0, columnspan=2, padx=10, pady=10, sticky="ew") self.button_frame.grid_columnconfigure(0, weight=1) self.button_frame.grid_columnconfigure(1, weight=1) self.button_frame.grid_columnconfigure(2, weight=1) # For Clear Log Button self.start_button = Button(self.button_frame, text="Start Holding Key", command=self.controller.start_key_press, bg="#2aa198", fg="white", font=('Inter', 12, 'bold')) self.start_button.grid(row=0, column=0, padx=5, pady=5, sticky="ew") self.stop_button = Button(self.button_frame, text="Stop Key Press (or F6)", command=self.controller.stop_key_press, bg="#dc322f", fg="white", font=('Inter', 12, 'bold')) self.stop_button.grid(row=0, column=1, padx=5, pady=5, sticky="ew") self.stop_button.config(state=tk.DISABLED) self.clear_log_button = Button(self.button_frame, text="Clear Log", command=self._clear_log, font=('Inter', 9)) self.clear_log_button.grid(row=0, column=2, padx=5, pady=5, sticky="ew") # --- Log Display Area --- self.log_frame = tk.LabelFrame(self, text="Activity Log (Jarvis's Observations)", padx=10, pady=10, font=('Consolas', 10, 'bold')) self.log_frame.grid(row=2, column=0, columnspan=2, padx=10, pady=10, sticky="nsew") self.log_frame.grid_rowconfigure(0, weight=1) self.log_frame.grid_columnconfigure(0, weight=1) self.log_text_area = scrolledtext.ScrolledText(self.log_frame, state='disabled', wrap='word', width=60, height=15, bg="#eee8d5", fg="#586e75", font=('Consolas', 10)) self.log_text_area.grid(row=0, column=0, sticky="nsew") # Initial population of window list is now triggered by controller's initial_setup_after_view_is_ready() self.master.after(100, self._poll_message_queue) # --- View Update Methods (Called by Controller) --- def update_window_list(self, window_titles, current_selected_title): """Updates the combobox with new window titles.""" self.window_combobox['values'] = window_titles self.target_window_title_var.set(current_selected_title) def get_key_input(self): """Returns the current value of the key input entry.""" return self.key_to_press_var.get().strip() def get_selected_window_title(self): """Returns the currently selected window title from the combobox.""" return self.target_window_title_var.get() def set_ui_state_running(self): """Sets UI elements to a 'running' state.""" self.start_button.config(state=tk.DISABLED) self.stop_button.config(state=tk.NORMAL) self.key_input_entry.config(state=tk.DISABLED) self.window_combobox.config(state=tk.DISABLED) self.refresh_button.config(state=tk.DISABLED) # Validation labels are hidden by UIController when changing state def set_ui_state_idle(self): """Sets UI elements to an 'idle' state.""" self.start_button.config(state=tk.NORMAL) self.stop_button.config(state=tk.DISABLED) self.key_input_entry.config(state=tk.NORMAL) self.window_combobox.config(state="readonly") self.refresh_button.config(state=tk.NORMAL) # Validation labels visibility will be managed by UIController's _check_start_button_state_ui() def show_input_error(self, message): """Displays a messagebox error for input validation.""" messagebox.showerror("Input Error", message) def set_key_validation_visibility(self, visible): """Controls visibility of the key validation label.""" if visible: self.key_validation_label.grid() else: self.key_validation_label.grid_remove() def set_window_validation_visibility(self, visible): """Controls visibility of the window validation label.""" if visible: self.target_window_validation_label.grid() else: self.target_window_validation_label.grid_remove() def _on_window_selected_event(self, event): """Internal handler for combobox selection event, calls controller.""" # This now directly calls the main controller, which will then use the UIController self.controller.on_window_selected() def _poll_message_queue(self): """Periodically checks the message queue for log updates.""" message_queue = self.controller.get_message_queue() while True: try: record = message_queue.get(block=False) self.log_text_area.configure(state='normal') # Add current timestamp to log entries for better tracking timestamp_str = datetime.datetime.now().strftime('%H:%M:%S') self.log_text_area.insert(tk.END, f"{timestamp_str} - {record}\n") self.log_text_area.see(tk.END) self.log_text_area.configure(state='disabled') except queue.Empty: break self.master.after(100, self._poll_message_queue) def _clear_log(self): """Clears the content of the log text area.""" self.log_text_area.configure(state='normal') self.log_text_area.delete(1.0, tk.END) self.log_text_area.configure(state='disabled')