182 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import serial
 | |
| import time
 | |
| import keyboard
 | |
| import serial.tools.list_ports as list_ports
 | |
| import mss
 | |
| import numpy as np
 | |
| import sys
 | |
| import pystray
 | |
| from PIL import Image, ImageDraw
 | |
| import threading
 | |
| import ctypes
 | |
| import os
 | |
| 
 | |
| # Set the title for the PowerShell window
 | |
| ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller")
 | |
| 
 | |
| # Set the process name for Task Manager
 | |
| try:
 | |
|     import ctypes
 | |
|     ctypes.windll.kernel32.SetConsoleTitleW("ESP32 Discord Controller")
 | |
|     os.system("title ESP32 Discord Controller")
 | |
| except:
 | |
|     pass
 | |
| 
 | |
| 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())
 | |
|     if not ports:
 | |
|         print("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
 | |
| 
 | |
| def get_discord_status():
 | |
|     with mss.mss() as sct:
 | |
|         # Define the region where the mute and deafen icons are located
 | |
|         mute_region = {"top": y, "left": x, "width": width, "height": height}
 | |
|         deafen_region = {"top": y2, "left": x2, "width": width, "height": height}
 | |
|         
 | |
|         # Capture the screen region
 | |
|         mute_screenshot = sct.grab(mute_region)
 | |
|         deafen_screenshot = sct.grab(deafen_region)
 | |
|         
 | |
|         # Convert the screenshots to numpy arrays
 | |
|         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
 | |
|              mute_image[i, j, 1] == expected_g and
 | |
|              mute_image[i, j, 0] == expected_b)
 | |
|             for i in range(grid) for j in range(grid)
 | |
|         )
 | |
|         deafen_status = any(
 | |
|             (deafen_image[i, j, 2] == expected_r and
 | |
|              deafen_image[i, j, 1] == expected_g and
 | |
|              deafen_image[i, j, 0] == expected_b)
 | |
|             for i in range(grid) for j in range(grid)
 | |
|         )
 | |
|         return mute_status, deafen_status
 | |
| 
 | |
| def create_image():
 | |
|     # Generate an image for the system tray icon
 | |
|     width = 64
 | |
|     height = 64
 | |
|     image = Image.new('RGB', (width, height), (255, 255, 255))
 | |
|     dc = ImageDraw.Draw(image)
 | |
|     dc.rectangle(
 | |
|         [(width // 2, 0), (width, height // 2)],
 | |
|         fill="black")
 | |
|     dc.rectangle(
 | |
|         [(0, height // 2), (width // 2, height)],
 | |
|         fill="black")
 | |
|     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)
 | |
| 
 | |
| def on_quit(icon, item):
 | |
|     icon.stop()
 | |
|     if 'ser' in globals() and ser.is_open:
 | |
|         ser.close()
 | |
|         print("Serial connection closed.")
 | |
|     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)
 | |
| 
 | |
| 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()
 | |
| 
 | |
| def main():
 | |
|     global ser
 | |
|     port = get_serial_port()
 | |
|     if not port:
 | |
|         return
 | |
|     
 | |
|     try:
 | |
|         ser = serial.Serial(port, 115200, timeout=1)
 | |
|         time.sleep(2)  # Wait for the connection to initialize
 | |
|         print("Listening for commands...")
 | |
|         
 | |
|         last_mute_status, last_deafen_status = get_discord_status()
 | |
|         print(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()
 | |
|         
 | |
|         while True:
 | |
|             try:
 | |
|                 if ser.in_waiting > 0:
 | |
|                     line = ser.readline().decode('utf-8').strip()
 | |
|                     print(f"Received: {line}")
 | |
|                     
 | |
|                     if line == "mute":
 | |
|                         keyboard.send('ctrl+shift+f16')
 | |
|                     elif line == "deafen":
 | |
|                         keyboard.send('ctrl+shift+f15')
 | |
|                     elif line == "status":
 | |
|                         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}")
 | |
|                     
 | |
|                 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}")
 | |
|                     last_mute_status, last_deafen_status = current_mute_status, current_deafen_status
 | |
|                 
 | |
|                 time.sleep(0.1)
 | |
|             except KeyboardInterrupt:
 | |
|                 print("Exiting program.")
 | |
|                 break
 | |
|             except Exception as e:
 | |
|                 print(f"Error during execution: {e}")
 | |
|                 break
 | |
|     
 | |
|     except serial.SerialException as e:
 | |
|         print(f"Could not open serial port: {e}")
 | |
|     finally:
 | |
|         if 'ser' in globals() and ser.is_open:
 | |
|             ser.close()
 | |
|             print("Serial connection closed.")
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |