diff --git a/DISCORD.lnk b/DISCORD.lnk deleted file mode 100644 index ba7d26d..0000000 Binary files a/DISCORD.lnk and /dev/null differ diff --git a/README.md b/README.md index 7c007b7..28a27ac 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,6 @@ This project allows you to control Discord mute and deafen status using an ESP32 - An ESP32 device - A USB cable to connect the ESP32 to your computer -### Python Packages - -Install the required Python packages using pip: - -```sh -pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow -``` - ### Clone the Repository Clone this repository to your local machine: @@ -28,14 +20,38 @@ git clone https://github.com/yourusername/ESP32-discord.git cd ESP32-discord ``` +### Windows Installation + +Run the following batch file to set up the virtual environment and install the required Python packages: + +```sh +install_windows.bat +``` + +### Linux Installation + +Run the following shell script to set up the virtual environment and install the required Python packages: + +```sh +./install_linux.sh +``` + ## Usage ### Running the Script You can run the script with the following command: +#### Windows + ```sh -python main.py +start.bat +``` + +#### Linux + +```sh +./start.sh ``` ### Specifying the COM Port @@ -43,13 +59,17 @@ python main.py You can specify the COM port directly when running the script: ```sh -python main.py -com=COM3 +pythonw main.pyw -com=COM3 ``` ### Hiding the Console Window If the COM port is specified, the script will hide the console window and run in the system tray. You can quit the application from the tray icon. +### GUI + +The script now includes a GUI that looks like Windows 11 dark mode. It will automatically hide the console window and show the GUI. + ## Notes - Ensure that your ESP32 device is connected to your computer via USB. diff --git a/install_linux.sh b/install_linux.sh new file mode 100644 index 0000000..ebc8ead --- /dev/null +++ b/install_linux.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Create a virtual environment +python3 -m venv .venv + +# Activate the virtual environment +source .venv/bin/activate + +# Install the required Python packages +pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow + +# Deactivate the virtual environment +deactivate + +echo "Installation complete. You can now run the application using start.sh." diff --git a/install_windows.bat b/install_windows.bat new file mode 100644 index 0000000..4d81ab2 --- /dev/null +++ b/install_windows.bat @@ -0,0 +1,15 @@ +@echo off +REM Create a virtual environment +python -m venv .venv + +REM Activate the virtual environment +call .venv\Scripts\activate + +REM Install the required Python packages +pip install pyserial keyboard pygetwindow pyautogui mss numpy pystray pillow + +REM Deactivate the virtual environment +deactivate + +echo Installation complete. You can now run the application using start.bat. +pause diff --git a/main.py b/main.pyw similarity index 61% rename from main.py rename to main.pyw index a3b8812..3134f19 100644 --- a/main.py +++ b/main.pyw @@ -10,6 +10,25 @@ from PIL import Image, ImageDraw import threading import ctypes import os +import tkinter as tk +from tkinter import messagebox +from tkinter import ttk + +# Define the region where the mute and deafen icons are located +x = -1772 +y = 1064 +x2 = -1746 +y2 = 1063 + +# Define the size of the region to check +width = 4 +height = 4 +grid = 4 + +# Define the expected color of the mute and deafen icons +expected_r = 242 +expected_g = 63 +expected_b = 67 # Set the title for the PowerShell window ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller") @@ -26,26 +45,32 @@ def get_serial_port(): if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): return sys.argv[1].split("=")[1] - ports = list(list_ports.comports()) + ports = [port for port in list(list_ports.comports()) if port.device != "COM1"] if not ports: - print("No serial ports found. Please connect a device.") + messagebox.showerror("Error", "No serial ports found. Please connect a device.") return None - print("Available Ports:") - for i, port in enumerate(ports): - print(f"{i}: {port.device}") - choice = int(input("Select a port by number: ")) - return ports[choice].device - -x = -1772 -y = 1064 -x2 = -1746 -y2 = 1063 -width = 4 -height = 4 -expected_r = 242 -expected_g = 63 -expected_b = 67 -grid = 4 + + if len(ports) == 1: + return ports[0].device + + port_choices = [port.device for port in ports] + + def on_select(): + selected_port.set(port_listbox.get(port_listbox.curselection())) + port_window.destroy() + + port_window = tk.Tk() + port_window.title("Select Serial Port") + port_window.configure(bg="#1e1e1e") + tk.Label(port_window, text="Available Ports:", bg="#1e1e1e", fg="#ffffff").pack() + port_listbox = tk.Listbox(port_window, bg="#2d2d2d", fg="#ffffff", selectbackground="#0078d7") + for port in port_choices: + port_listbox.insert(tk.END, port) + port_listbox.pack() + selected_port = tk.StringVar() + tk.Button(port_window, text="Select", command=on_select, bg="#0078d7", fg="#ffffff").pack() + port_window.mainloop() + return selected_port.get() def get_discord_status(): with mss.mss() as sct: @@ -61,10 +86,6 @@ def get_discord_status(): mute_image = np.array(mute_screenshot) deafen_image = np.array(deafen_screenshot) - # # Save the screenshots to files - # mss.tools.to_png(mute_screenshot.rgb, mute_screenshot.size, output="mute_screenshot.png") - # mss.tools.to_png(deafen_screenshot.rgb, deafen_screenshot.size, output="deafen_screenshot.png") - # Check the pixel color in a 2x2 region mute_status = any( (mute_image[i, j, 2] == expected_r and @@ -95,32 +116,35 @@ def create_image(): return image def toggle_console(): - whnd = ctypes.windll.kernel32.GetConsoleWindow() - if whnd != 0: - if ctypes.windll.user32.IsWindowVisible(whnd): - ctypes.windll.user32.ShowWindow(whnd, 0) - else: - ctypes.windll.user32.ShowWindow(whnd, 1) + if console_window.state() == "normal": + console_window.withdraw() + else: + console_window.deiconify() + +def log_message(message): + log_text.insert(tk.END, message + "\n") + log_text.see(tk.END) def on_quit(icon, item): icon.stop() if 'ser' in globals() and ser.is_open: ser.close() - print("Serial connection closed.") + log_message("Serial connection closed.") + console_window.withdraw() + console_window.quit() sys.exit(0) def hide_console(): - whnd = ctypes.windll.kernel32.GetConsoleWindow() - if whnd != 0: - ctypes.windll.user32.ShowWindow(whnd, 0) - ctypes.windll.kernel32.CloseHandle(whnd) + log_message("Hiding console window...") + time.sleep(2) + console_window.withdraw() def hide_in_tray(): - hide_console() icon = pystray.Icon("ESP32-discord") icon.icon = create_image() icon.menu = pystray.Menu(pystray.MenuItem('Quit', on_quit), pystray.MenuItem('Toggle Console', toggle_console)) threading.Thread(target=icon.run).start() + hide_console() def main(): global ser @@ -131,20 +155,20 @@ def main(): try: ser = serial.Serial(port, 115200, timeout=1) time.sleep(2) # Wait for the connection to initialize - print("Listening for commands...") + log_message("Listening for commands...") last_mute_status, last_deafen_status = get_discord_status() - print(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}") + log_message(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}") ser.write(f"Mute: {last_mute_status}, Deafen: {last_deafen_status}\n".encode('utf-8')) - if len(sys.argv) > 1 and sys.argv[1].startswith("-com="): - hide_in_tray() + hide_in_tray() + while True: try: if ser.in_waiting > 0: line = ser.readline().decode('utf-8').strip() - print(f"Received: {line}") + log_message(f"Received: {line}") if line == "mute": keyboard.send('ctrl+shift+f16') @@ -154,28 +178,39 @@ def main(): mute_status, deafen_status = get_discord_status() ser.write(f"Mute: {mute_status}, Deafen: {deafen_status}\n".encode('utf-8')) else: - print(f"Unknown command: {line}") + log_message(f"Unknown command: {line}") current_mute_status, current_deafen_status = get_discord_status() if current_mute_status != last_mute_status or current_deafen_status != last_deafen_status: ser.write(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}\n".encode('utf-8')) - print(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}") + log_message(f"Mute: {current_mute_status}, Deafen: {current_deafen_status}") last_mute_status, last_deafen_status = current_mute_status, current_deafen_status time.sleep(0.1) except KeyboardInterrupt: - print("Exiting program.") + log_message("Exiting program.") break except Exception as e: - print(f"Error during execution: {e}") + log_message(f"Error during execution: {e}") break except serial.SerialException as e: - print(f"Could not open serial port: {e}") + messagebox.showerror("Error", f"Could not open serial port: {e}") finally: if 'ser' in globals() and ser.is_open: ser.close() - print("Serial connection closed.") + log_message("Serial connection closed.") if __name__ == "__main__": - main() + console_window = tk.Tk() + console_window.title("ESP32 Discord Controller") + console_window.configure(bg="#1e1e1e") + style = ttk.Style() + style.theme_use('clam') + style.configure("TLabel", background="#1e1e1e", foreground="#ffffff") + style.configure("TButton", background="#0078d7", foreground="#ffffff") + style.configure("TText", background="#2d2d2d", foreground="#ffffff") + log_text = tk.Text(console_window, wrap=tk.WORD, bg="#2d2d2d", fg="#ffffff") + log_text.pack(expand=True, fill=tk.BOTH) + threading.Thread(target=main).start() + console_window.mainloop() diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..120b8c5 --- /dev/null +++ b/start.bat @@ -0,0 +1,9 @@ +@echo off +REM Activate the virtual environment +call .venv\Scripts\activate + +REM Run the Python script +start pythonw main.pyw + +REM Deactivate the virtual environment +deactivate diff --git a/start.ps1 b/start.ps1 index c04a173..714c68d 100644 --- a/start.ps1 +++ b/start.ps1 @@ -2,7 +2,7 @@ & .venv\Scripts\activate # Run the Python script -python main.py -com=COM3 +pythonw main.pyw # Deactivate the virtual environment deactivate \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..8ba8229 --- /dev/null +++ b/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Activate the virtual environment +source .venv/bin/activate + +# Run the Python script +pythonw main.pyw & + +# Deactivate the virtual environment +deactivate