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 .vscode/settings.json
shortcut.txt shortcut.txt
src/__pycache__/config.cpython-313.pyc src/__pycache__/config.cpython-313.pyc
src/__pycache__/startup.cpython-313.pyc

View File

@@ -1,6 +1,5 @@
@echo off @echo off
REM run.bat cd /d "%~dp0"
REM Activates the virtual environment and runs your main Python script.
REM Activate the virtual environment REM Activate the virtual environment
call venv\Scripts\activate.bat 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 @echo off
REM run.bat cd /d "%~dp0"
REM Activates the virtual environment and runs your main Python script.
REM Activate the virtual environment
call venv\Scripts\activate.bat 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 start "OopsWrongLang" /B pythonw src\main.pyw
echo application is running in the background. you can close this window.
pause pause

Binary file not shown.

Binary file not shown.

View File

@@ -1,14 +1,46 @@
import os import os
import json
import keyboard import keyboard
import time 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(): def get_shortcut():
""" """
Retrieves the shortcut from the config file. 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 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.") print("It seems this is the first time you are running the application.")
while True: while True:
print("Please press the key combination you want to use as a shortcut and then press ESC.") 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}") print(f"You pressed: {shortcut}")
confirm = input("Is this correct? (y/n): ").lower() confirm = input("Is this correct? (y/n): ").lower()
if confirm == 'y': if confirm == 'y':
with open(CONFIG_FILE, "w") as f: config["shortcut"] = shortcut
f.write(shortcut) save_config(config)
return shortcut return shortcut
else: else:
print("Let's try again.") print("Let's try again.")
else: return config["shortcut"]
with open(CONFIG_FILE, "r") as f:
return f.read().strip()
if __name__ == "__main__": if __name__ == "__main__":
shortcut = get_shortcut() config = load_config()
print(f"Your shortcut is set to: {shortcut}") print(f"Your shortcut is set to: {config.get('shortcut', 'Not set')}")
print("You can now use this shortcut in the application.") print(f"Run on startup is set to: {config.get('run_on_startup', 'Not set')}")
print('do you want to change the shortcut? (y/n): ', end='') 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': if input().lower() == 'y':
while True: while True:
time.sleep(0.2) time.sleep(0.2)
print("Please press the key combination you want to use as a shortcut and then press ESC.") print("Please press the key combination you want to use as a shortcut and then press ESC.")
new_shortcut = keyboard.read_hotkey(suppress=False) new_shortcut = keyboard.read_hotkey(suppress=False)
print(f"You pressed: {new_shortcut}") 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() confirm = input("Is this correct? (y/n): ").lower()
if confirm.lower() == 'y': if confirm.lower() == 'y':
with open(CONFIG_FILE, "w") as f: config['shortcut'] = new_shortcut
f.write(new_shortcut) save_config(config)
print("Shortcut updated successfully.") print("Shortcut updated successfully.")
break break
else: else:
print("Let's try again.") print("Let's try again.")
else: else:
print("No changes made to the shortcut.") print("No changes made to the shortcut.")
print("Exiting without changes.") print("Exiting without changes.")
input("Press Enter to exit.") input("Press Enter to exit.")

View File

@@ -8,7 +8,8 @@ import threading
import pystray import pystray
from PIL import Image from PIL import Image
import re 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): def convert_en_characters(input_str):
""" """
@@ -121,21 +122,53 @@ def on_shortcut():
print(f"Converted text: {converted_text}") print(f"Converted text: {converted_text}")
keyboard.press_and_release('ctrl+v') # Paste the converted text keyboard.press_and_release('ctrl+v') # Paste the converted text
time.sleep(0.2) 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): def quit_app(icon, item):
icon.stop() icon.stop()
import os import os
os._exit(0) os._exit(0)
def setup_tray(): def setup_tray(config):
image = Image.open("assets/icon.png") # Make sure icon.png exists in your project folder def on_toggle_lang_change(icon, item):
menu = pystray.Menu(pystray.MenuItem('Quit', quit_app)) 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 = pystray.Icon("oopswronglang", image, "OopsWrongLang", menu)
icon.run() icon.run()
def main(): 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 # 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() tray_thread.start()
# Register the keyboard shortcut # Register the keyboard shortcut
@@ -144,7 +177,7 @@ def main():
print(f"Press {shortcut} to convert text to Persian.") print(f"Press {shortcut} to convert text to Persian.")
# Keep the script running # Keep the script running
keyboard.wait() keyboard.wait(suppress=True)
if __name__ == "__main__": if __name__ == "__main__":
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