Untitled
unknown
plain_text
a year ago
14 kB
6
Indexable
import customtkinter as ctk
import subprocess
import threading
from tkinter import StringVar
class TouchKeyboard(ctk.CTkFrame):
def __init__(self, master, entry_widget, hide_callback, **kwargs):
super().__init__(master, **kwargs)
self.entry = entry_widget
self.hide_callback = hide_callback
self.shift_on = False
# Layout settings for the keyboard
self.layouts = {
'default': [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü'],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä'],
['⇧', 'y', 'x', 'c', 'v', 'b', 'n', 'm', '⌫'],
['#+=', ' ', '↵', '⌨']
],
'shift': [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
['Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', 'O', 'P', 'Ü'],
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Ö', 'Ä'],
['⇧', 'Y', 'X', 'C', 'V', 'B', 'N', 'M', '⌫'],
['#+=', ' ', '↵', '⌨']
],
'special': [
['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'],
['-', '_', '=', '+', '[', ']', '{', '}', '\\', '|'],
['/', ':', ';', '"', '\'', ',', '.', '?', '<', '>'],
['ABC', '~', '`', '€', '£', '¥', '§', '⌫'],
['123', ' ', '↵', '⌨']
]
}
self.current_layout = 'default'
self.create_keyboard()
def create_keyboard(self):
# Clear existing buttons
for widget in self.winfo_children():
widget.destroy()
# Create keyboard layout
layout = self.layouts[self.current_layout]
for row_idx, row in enumerate(layout):
row_frame = ctk.CTkFrame(self, fg_color="transparent")
row_frame.grid(row=row_idx, column=0, pady=2)
for col_idx, key in enumerate(row):
# Determine button width based on key
width = 65 if key not in ['⌫', '⇧', '#+=', 'ABC', '123', ' ', '↵', '⌨'] else 90
if key == ' ':
width = 200
btn = ctk.CTkButton(
row_frame,
text=key,
width=width,
height=50,
command=lambda k=key: self.key_press(k)
)
btn.grid(row=0, column=col_idx, padx=2)
def key_press(self, key):
if key == '⌫':
current = self.entry.get()
self.entry.delete(0, 'end')
self.entry.insert(0, current[:-1])
elif key == '⇧':
self.current_layout = 'default' if self.current_layout == 'shift' else 'shift'
self.create_keyboard()
elif key == '#+=':
self.current_layout = 'special'
self.create_keyboard()
elif key == 'ABC' or key == '123':
self.current_layout = 'default'
self.create_keyboard()
elif key == '↵':
# Enter key functionality
pass
elif key == '⌨':
self.hide_callback()
else:
current_pos = self.entry.index('insert')
self.entry.insert(current_pos, key)
class WifiConfiguratorApp(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Wi-Fi Configurator")
self.geometry("1024x600")
self.resizable(False, False)
# Variables
self.networks = []
self.selected_network = StringVar()
self.password = StringVar()
self.show_password = ctk.BooleanVar(value=False)
self.keyboard_visible = False
self.current_connection = {
"SSID": "Not connected",
"Signal Strength": "N/A",
"IP Address": "N/A"
}
self.status_message = StringVar(value="Idle")
# Create main container
self.main_container = ctk.CTkFrame(self)
self.main_container.pack(fill="both", expand=True)
# Create UI Elements
self.create_widgets()
self.scan_wifi_networks()
self.update_current_connection()
def create_widgets(self):
# Top section (always visible)
self.top_frame = ctk.CTkFrame(self.main_container)
self.top_frame.pack(fill="x", padx=20, pady=10)
# Title and Status
title_label = ctk.CTkLabel(
self.top_frame,
text="Wi-Fi Configurator",
font=("Arial", 32, "bold")
)
title_label.pack(pady=(10, 5))
self.status_label = ctk.CTkLabel(
self.top_frame,
textvariable=self.status_message,
font=("Arial", 16)
)
self.status_label.pack(pady=5)
# Content section
self.content_frame = ctk.CTkFrame(self.main_container)
self.content_frame.pack(fill="both", expand=True, padx=20)
# Network selection
network_label = ctk.CTkLabel(
self.content_frame,
text="Select Network:",
font=("Arial", 16)
)
network_label.pack(pady=(20, 5))
self.network_dropdown = ctk.CTkOptionMenu(
self.content_frame,
variable=self.selected_network,
values=self.networks,
width=300,
height=40
)
self.network_dropdown.pack(pady=5)
# Password entry
password_label = ctk.CTkLabel(
self.content_frame,
text="Password:",
font=("Arial", 16)
)
password_label.pack(pady=(20, 5))
self.password_entry = ctk.CTkEntry(
self.content_frame,
textvariable=self.password,
show="*",
width=300,
height=40
)
self.password_entry.pack(pady=5)
self.password_entry.bind("<FocusIn>", self.show_keyboard)
# Connection info (collapsible)
self.connection_frame = ctk.CTkFrame(self.content_frame)
self.connection_frame.pack(fill="x", pady=20)
self.ssid_label = ctk.CTkLabel(
self.connection_frame,
text="SSID: Not connected",
font=("Arial", 14)
)
self.ssid_label.pack(pady=2)
self.signal_label = ctk.CTkLabel(
self.connection_frame,
text="Signal Strength: N/A",
font=("Arial", 14)
)
self.signal_label.pack(pady=2)
self.ip_label = ctk.CTkLabel(
self.connection_frame,
text="IP Address: N/A",
font=("Arial", 14)
)
self.ip_label.pack(pady=2)
# Action buttons
button_frame = ctk.CTkFrame(self.content_frame)
button_frame.pack(pady=20)
ctk.CTkButton(
button_frame,
text="Connect",
command=self.start_connecting_to_wifi,
width=120,
height=40
).grid(row=0, column=0, padx=10)
ctk.CTkButton(
button_frame,
text="Refresh",
command=self.scan_wifi_networks,
width=120,
height=40
).grid(row=0, column=1, padx=10)
# Keyboard container (hidden initially)
self.keyboard_frame = ctk.CTkFrame(self.main_container)
self.keyboard = TouchKeyboard(
self.keyboard_frame,
self.password_entry,
self.hide_keyboard,
fg_color="transparent"
)
self.keyboard.pack(pady=10)
def show_keyboard(self, event=None):
if not self.keyboard_visible:
self.connection_frame.pack_forget() # Hide connection info
self.keyboard_frame.pack(fill="x", padx=20, pady=10)
self.keyboard_visible = True
def hide_keyboard(self):
if self.keyboard_visible:
self.keyboard_frame.pack_forget()
self.connection_frame.pack(fill="x", pady=20) # Show connection info
self.keyboard_visible = False
def update_status_appearance(self):
message = self.status_message.get().lower()
if "success" in message or "connected" in message:
self.status_label.configure(text_color="green")
elif "error" in message or "failed" in message or "incorrect" in message:
self.status_label.configure(text_color="red")
else:
self.status_label.configure(text_color="gray")
# Keep all existing methods for WiFi functionality
def scan_wifi_networks(self):
self.status_message.set("Scanning for Wi-Fi networks...")
self.update_status_appearance()
threading.Thread(target=self._scan_wifi_networks_thread).start()
def _scan_wifi_networks_thread(self):
try:
result = subprocess.run(
["nmcli", "-t", "-f", "SSID,SIGNAL", "dev", "wifi"],
capture_output=True, text=True
)
if result.returncode == 0:
networks = []
for line in result.stdout.split("\n"):
if line and line.split(":")[0]:
ssid, _ = line.split(":")
if ssid and ssid not in networks:
networks.append(ssid)
self.networks = networks
self.network_dropdown.configure(values=self.networks)
if self.networks:
self.selected_network.set(self.networks[0])
self.status_message.set("Wi-Fi scan completed.")
else:
self.status_message.set("Failed to scan Wi-Fi networks.")
self.update_status_appearance()
except Exception as e:
self.status_message.set(f"Error: {e}")
self.update_status_appearance()
def start_connecting_to_wifi(self):
threading.Thread(target=self.connect_to_wifi).start()
def connect_to_wifi(self):
ssid = self.selected_network.get()
password = self.password.get()
if not ssid:
self.status_message.set("Please select a Wi-Fi network.")
self.update_status_appearance()
return
self.status_message.set(f"Connecting to {ssid}...")
self.update_status_appearance()
try:
result = subprocess.run(
["nmcli", "dev", "wifi", "connect", ssid, "password", password],
capture_output=True, text=True
)
if result.returncode == 0:
self.status_message.set(f"Successfully connected to {ssid}.")
self.update_current_connection()
else:
error_message = result.stderr.strip()
if "802-11-wireless-security.psk: property is invalid" in error_message:
self.status_message.set("Incorrect password. Please try again.")
elif "No network with SSID" in error_message:
self.status_message.set("The selected Wi-Fi network is unavailable.")
else:
self.status_message.set(f"Connection failed: {error_message}")
self.password.set("")
self.update_status_appearance()
except Exception as e:
self.status_message.set(f"Error: {e}")
self.update_status_appearance()
def update_current_connection(self):
try:
ssid_result = subprocess.run(
["nmcli", "-t", "-f", "ACTIVE,SSID,SIGNAL", "dev", "wifi"],
capture_output=True, text=True
)
ip_result = subprocess.run(
["hostname", "-I"], capture_output=True, text=True
)
if ssid_result.returncode == 0:
for line in ssid_result.stdout.split("\n"):
if line.startswith("yes"):
_, ssid, signal = line.split(":")
self.current_connection["SSID"] = ssid
self.current_connection["Signal Strength"] = f"{signal}%"
break
else:
self.current_connection["SSID"] = "Not connected"
self.current_connection["Signal Strength"] = "N/A"
if ip_result.returncode == 0:
self.current_connection["IP Address"] = ip_result.stdout.strip()
else:
self.current_connection["IP Address"] = "N/A"
self.ssid_label.configure(text=f"SSID: {self.current_connection['SSID']}")
self.signal_label.configure(text=f"Signal Strength: {self.current_connection['Signal Strength']}")
self.ip_label.configure(text=f"IP Address: {self.current_connection['IP Address']}")
except Exception as e:
self.status_message.set(f"Failed to retrieve connection details: {e}")
self.update_status_appearance()
if __name__ == "__main__":
ctk.set_appearance_mode("Dark") # Modern dark theme
ctk.set_default_color_theme("blue")
app = WifiConfiguratorApp()
app.mainloop()Editor is loading...
Leave a Comment