137 lines
7.5 KiB
Python
137 lines
7.5 KiB
Python
import tkinter as tk
|
|
from tkinter import messagebox
|
|
import logging
|
|
|
|
from model.model import KeyPressModel
|
|
from view.view import KeyPressView
|
|
# NEW: Import UIController
|
|
from controller.ui_controller import UIController
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class KeyPressController:
|
|
def __init__(self, model, view):
|
|
self.model = model
|
|
self.view = view # This will be set by main.py after View is instantiated.
|
|
self.ui_controller = None # Will be instantiated and linked after view is set.
|
|
logger.info("Controller: Initialized (view and UIController might be None for now).")
|
|
|
|
# Register this controller's callback with the Model for AHK stopping events
|
|
self.model.register_ahk_stopped_callback(self._handle_ahk_external_stop)
|
|
|
|
def initial_setup_after_view_is_ready(self):
|
|
"""
|
|
Performs controller setup that relies on the view being fully initialized.
|
|
Called from main.py after controller.view is set.
|
|
"""
|
|
if self.view is None:
|
|
logger.error("Controller: initial_setup_after_view_is_ready called but view is None!")
|
|
return
|
|
|
|
# Instantiate UIController and pass itself (main controller) and the view
|
|
self.ui_controller = UIController(self, self.view)
|
|
self.ui_controller.initial_ui_setup_after_view_is_ready() # Trigger UIController's setup
|
|
|
|
logger.info("Controller: Performing post-view-initialization setup.")
|
|
# Initial set for key based on UI default
|
|
self.model.set_key_to_press(self.view.get_key_input())
|
|
# Initial window refresh and selection handled by ui_controller.refresh_windows_ui()
|
|
|
|
|
|
# --- Methods called by UIController to update Model/Controller state ---
|
|
def set_key_input_from_ui(self, key_str):
|
|
"""Receives key input from UI, updates model."""
|
|
self.model.set_key_to_press(key_str)
|
|
|
|
def set_window_selection_from_ui(self, selected_title):
|
|
"""Receives window selection from UI, updates model based on AHK logic."""
|
|
if selected_title == "--- Global Input (No Specific Window) ---":
|
|
# As per user's explicit request: "it is always a specific window", no "GLOBAL" AHK branch.
|
|
# This selection means AHK script will likely not find a window, thus releasing the key.
|
|
self.model.set_target_window("INVALID_GLOBAL_TARGET_FOR_AHK") # Use a distinct string for internal model logic
|
|
self.ui_controller.show_ui_error_message("Warning: 'Global Input' selected. The AutoHotkey script is designed for specific windows and will likely NOT press the key automatically with this selection.")
|
|
logger.warning("Controller: 'Global Input' selected. AHK logic is non-global; key will not be pressed.")
|
|
elif selected_title == "--- Select a Window ---":
|
|
self.model.set_target_window("")
|
|
logger.info("Controller: No specific window selected. Target is empty.")
|
|
else:
|
|
self.model.set_target_window(selected_title)
|
|
logger.info(f"Controller: Target window set to: '{selected_title}'")
|
|
|
|
# --- Methods for UIController to query Model ---
|
|
def get_available_window_titles(self):
|
|
"""Provides available window titles (from model) to UIController."""
|
|
return self.model.get_window_titles()
|
|
|
|
# --- Core Application Logic / Event Handlers (Called by UIController/View directly, or internally) ---
|
|
def _check_start_button_state(self):
|
|
"""
|
|
Internal method to check application state and update UI button state.
|
|
This is called by UIController after relevant inputs change.
|
|
"""
|
|
if self.ui_controller: # Ensure UIController is instantiated before calling its methods
|
|
self.ui_controller._check_start_button_state_ui() # Delegate to UIController for UI update
|
|
|
|
def start_key_press(self):
|
|
"""Handles the 'Start Holding Key' button click event (from View)."""
|
|
logger.info("Controller: Start key press requested.")
|
|
|
|
# Perform validation using UIController's methods to get current UI state
|
|
key_value = self.view.get_key_input() # Get current key from view
|
|
selected_window = self.view.get_selected_window_title() # Get current window from view
|
|
|
|
if not key_value:
|
|
self.ui_controller.show_ui_error_message("The 'Key to Press' field cannot be empty. What exactly do you expect me to press?")
|
|
self.view.set_key_validation_visibility(True)
|
|
logger.error("Controller: Aborting: Key to press field is empty.")
|
|
return
|
|
|
|
if selected_window == "--- Select a Window ---":
|
|
self.ui_controller.show_ui_error_message("Please select a specific target window or 'Global Input'.")
|
|
self.view.set_window_validation_visibility(True)
|
|
logger.error("Controller: Aborting: No target window selected.")
|
|
return
|
|
|
|
if selected_window == "--- Global Input (No Specific Window) ---":
|
|
# Show the warning again if the user is attempting to start with 'Global Input'
|
|
self.ui_controller.show_ui_error_message("Warning: 'Global Input' selected. The current AutoHotkey script is designed to activate a specific window, not provide global key presses. This option will prevent the key from being pressed automatically.")
|
|
logger.warning("Controller: Attempting to start with 'Global Input'. AHK logic is non-global. Key will not be pressed.")
|
|
|
|
# Tell Model to start AHK script. Model handles pynput listener internally.
|
|
if self.model.start_autohotkey_script():
|
|
self.ui_controller.set_ui_running_state() # Update UI via UIController
|
|
logger.info("Controller: Key press operation successfully initiated.")
|
|
else:
|
|
self.ui_controller.show_ui_error_message("Failed to start AutoHotkey script. Check application logs for details (e.g., AutoHotkey.exe not found).")
|
|
self.ui_controller.set_ui_idle_state() # Reset UI via UIController
|
|
logger.error("Controller: Failed to start AHK script. Aborting.")
|
|
|
|
def stop_key_press(self):
|
|
"""Handles the 'Stop Key Press' button click event (from View)."""
|
|
logger.info("Controller: Stop key press requested.")
|
|
self.model.stop_autohotkey_script() # Tell Model to stop AHK
|
|
self.ui_controller.set_ui_idle_state() # Set UI to idle state via UIController
|
|
logger.info("Controller: Key press operation stopped.")
|
|
|
|
def _handle_ahk_external_stop(self):
|
|
"""
|
|
Callback method invoked by the Model when the AHK script stops due to
|
|
an external event (e.g., AHK error, F6 press, window not found).
|
|
Resets the UI state via UIController.
|
|
"""
|
|
logger.info("Controller: AHK script stopped externally. Requesting UI reset.")
|
|
# Ensure this is scheduled on the main Tkinter thread if called from a background thread
|
|
if self.view and self.view.master:
|
|
self.view.master.after_idle(self.ui_controller.set_ui_idle_state)
|
|
else:
|
|
logger.warning("Controller: Cannot schedule UI reset, view or master is unavailable.")
|
|
|
|
def on_app_close(self):
|
|
"""Handles application window close event, ensures AHK cleanup."""
|
|
logger.info("Controller: Application close requested. Initiating cleanup.")
|
|
self.model.stop_autohotkey_script()
|
|
if self.view and self.view.master: # Check if master still exists before destroying
|
|
self.view.master.destroy()
|
|
logger.info("Controller: Application closed.")
|
|
|