Merge pull request #5 from Hamedrz004/feature/run-on-startup

Feature/run on startup,
adding system tray menue items.
This commit is contained in:
Hamed
2025-08-11 11:45:43 +03:30
committed by GitHub
9 changed files with 150 additions and 30 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.vscode/settings.json
shortcut.txt
src/__pycache__/config.cpython-313.pyc
src/__pycache__/startup.cpython-313.pyc

View File

@@ -1,6 +1,5 @@
@echo off
REM run.bat
REM Activates the virtual environment and runs your main Python script.
cd /d "%~dp0"
REM Activate the virtual environment
call venv\Scripts\activate.bat

5
config.json Normal file
View File

@@ -0,0 +1,5 @@
{
"run_on_startup": true,
"shortcut": "ctrl+shift+B",
"lang_change": true
}

View File

@@ -1,11 +1,9 @@
@echo off
REM run.bat
REM Activates the virtual environment and runs your main Python script.
cd /d "%~dp0"
REM Activate the virtual environment
call venv\Scripts\activate.bat
echo Starting the application...
REM Run your main Python script (replace main.py with your script name if different)
start "OopsWrongLang" /B pythonw src\main.pyw
echo application is running in the background. you can close this window.
pause

Binary file not shown.

Binary file not shown.

View File

@@ -1,14 +1,46 @@
import os
import json
import keyboard
import time
CONFIG_FILE = "shortcut.txt"
import msvcrt
CONFIG_FILE = "config.json"
SHORTCUT_FILE = "shortcut.txt" # For migrating old config
def load_config():
"""
Loads the configuration from config.json.
If the file doesn't exist, it creates it with default values.
It also migrates the old shortcut.txt if it exists.
"""
if not os.path.exists(CONFIG_FILE):
config = {"run_on_startup": False, "shortcut": "ctrl+shift+b","lang_change": True}
if os.path.exists(SHORTCUT_FILE):
with open(SHORTCUT_FILE, "r") as f:
shortcut = f.read().strip()
if shortcut:
config["shortcut"] = shortcut
os.remove(SHORTCUT_FILE) # remove old config file
save_config(config)
return config
else:
with open(CONFIG_FILE, "r") as f:
return json.load(f)
def save_config(config):
"""
Saves the configuration to config.json.
"""
with open(CONFIG_FILE, "w") as f:
json.dump(config, f, indent=4)
def get_shortcut():
"""
Retrieves the shortcut from the config file.
If the file doesn't exist, it prompts the user to create one by pressing the desired keys.
"""
if not os.path.exists(CONFIG_FILE):
config = load_config()
if "shortcut" not in config:
print("It seems this is the first time you are running the application.")
while True:
print("Please press the key combination you want to use as a shortcut and then press ESC.")
@@ -16,37 +48,40 @@ def get_shortcut():
print(f"You pressed: {shortcut}")
confirm = input("Is this correct? (y/n): ").lower()
if confirm == 'y':
with open(CONFIG_FILE, "w") as f:
f.write(shortcut)
config["shortcut"] = shortcut
save_config(config)
return shortcut
else:
print("Let's try again.")
else:
with open(CONFIG_FILE, "r") as f:
return f.read().strip()
return config["shortcut"]
if __name__ == "__main__":
shortcut = get_shortcut()
print(f"Your shortcut is set to: {shortcut}")
print("You can now use this shortcut in the application.")
print('do you want to change the shortcut? (y/n): ', end='')
config = load_config()
print(f"Your shortcut is set to: {config.get('shortcut', 'Not set')}")
print(f"Run on startup is set to: {config.get('run_on_startup', 'Not set')}")
print(f"Change language layout after transformation is set to: {config.get('lang_change', 'Not set')}")
print('Do you want to change the shortcut? (y/n): ', end='')
if input().lower() == 'y':
while True:
time.sleep(0.2)
print("Please press the key combination you want to use as a shortcut and then press ESC.")
new_shortcut = keyboard.read_hotkey(suppress=False)
print(f"You pressed: {new_shortcut}")
time.sleep(0.5)
time.sleep(0.01)
# Clear the input buffer
while msvcrt.kbhit():
msvcrt.getch()
confirm = input("Is this correct? (y/n): ").lower()
if confirm.lower() == 'y':
with open(CONFIG_FILE, "w") as f:
f.write(new_shortcut)
config['shortcut'] = new_shortcut
save_config(config)
print("Shortcut updated successfully.")
break
else:
print("Let's try again.")
else:
print("No changes made to the shortcut.")
print("Exiting without changes.")
input("Press Enter to exit.")
input("Press Enter to exit.")

View File

@@ -8,7 +8,8 @@ import threading
import pystray
from PIL import Image
import re
from config import get_shortcut
from config import load_config, save_config, get_shortcut
from startup import add_to_startup, remove_from_startup, is_in_startup
def convert_en_characters(input_str):
"""
@@ -121,21 +122,53 @@ def on_shortcut():
print(f"Converted text: {converted_text}")
keyboard.press_and_release('ctrl+v') # Paste the converted text
time.sleep(0.2)
keyboard.press_and_release('windows+space')
if load_config().get("lang_change", True):
# Change the keyboard layout to Persian
keyboard.press_and_release('windows+space')
def quit_app(icon, item):
icon.stop()
import os
os._exit(0)
def setup_tray():
image = Image.open("assets/icon.png") # Make sure icon.png exists in your project folder
menu = pystray.Menu(pystray.MenuItem('Quit', quit_app))
def setup_tray(config):
def on_toggle_lang_change(icon, item):
config["lang_change"] = not item.checked
save_config(config)
def on_toggle_startup(icon, item):
config["run_on_startup"] = not item.checked
save_config(config)
if config["run_on_startup"]:
add_to_startup()
else:
remove_from_startup()
image = Image.open("assets/icon.png")
menu = pystray.Menu(
pystray.MenuItem(f'Current Shortcut: {get_shortcut()}',lambda icon, item: None),
pystray.MenuItem(
'change keyboard language layout after transformation',
on_toggle_lang_change,
checked=lambda item: config["lang_change"]
),
pystray.MenuItem(
'Run on Startup',
on_toggle_startup,
checked=lambda item: config["run_on_startup"]
),
pystray.MenuItem('Quit', quit_app)
)
icon = pystray.Icon("oopswronglang", image, "OopsWrongLang", menu)
icon.run()
def main():
config = load_config()
# Sync startup state just in case it was changed externally
config["run_on_startup"] = is_in_startup()
save_config(config)
# Start the tray icon in a separate thread
tray_thread = threading.Thread(target=setup_tray, daemon=True)
tray_thread = threading.Thread(target=lambda: setup_tray(config), daemon=True)
tray_thread.start()
# Register the keyboard shortcut
@@ -144,7 +177,7 @@ def main():
print(f"Press {shortcut} to convert text to Persian.")
# Keep the script running
keyboard.wait()
keyboard.wait(suppress=True)
if __name__ == "__main__":
main()

49
src/startup.py Normal file
View File

@@ -0,0 +1,49 @@
import os
import winreg
APP_NAME = "OopsWrongLang"
RUN_BAT_PATH = os.path.abspath("run.bat")
def add_to_startup():
"""
Adds the application to Windows startup.
"""
try:
key = winreg.HKEY_CURRENT_USER
sub_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
print(f'bat file path: {RUN_BAT_PATH}')
with winreg.OpenKey(key, sub_key, 0, winreg.KEY_SET_VALUE) as registry_key:
winreg.SetValueEx(registry_key, APP_NAME, 0, winreg.REG_SZ, f'"{RUN_BAT_PATH}"')
except OSError as e:
print(f"Error adding to startup: {e}")
def remove_from_startup():
"""
Removes the application from Windows startup.
"""
try:
key = winreg.HKEY_CURRENT_USER
sub_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
with winreg.OpenKey(key, sub_key, 0, winreg.KEY_SET_VALUE) as registry_key:
winreg.DeleteValue(registry_key, APP_NAME)
except FileNotFoundError:
# This is fine, it means the key doesn't exist
pass
except OSError as e:
print(f"Error removing from startup: {e}")
def is_in_startup():
"""
Checks if the application is in Windows startup.
"""
try:
key = winreg.HKEY_CURRENT_USER
sub_key = r"Software\Microsoft\Windows\CurrentVersion\Run"
with winreg.OpenKey(key, sub_key, 0, winreg.KEY_READ) as registry_key:
winreg.QueryValueEx(registry_key, APP_NAME)
return True
except FileNotFoundError:
return False
except OSError as e:
print(f"Error checking startup status: {e}")
return False