Compare commits
12 Commits
bc0f4bc960
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c26e99dcf | ||
|
|
a701c0abd3 | ||
|
|
8463eb28df | ||
|
|
c23805320e | ||
|
|
66c0482ae3 | ||
|
|
9647115ad6 | ||
|
|
7fbd6ca080 | ||
|
|
4163d1cf6e | ||
|
|
fb12d5a216 | ||
|
|
9aa2ff2bd0 | ||
|
|
96a8092716 | ||
|
|
ad7ca318a7 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
.vscode/settings.json
|
||||
src/__pycache__/config.cpython-314.pyc
|
||||
src/__pycache__/startup.cpython-314.pyc
|
||||
|
||||
src/__pycache__/startup.cpython-314.pyc
|
||||
src/__pycache__/config.cpython-314.pyc
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
app.lock
|
||||
src/__pycache__/
|
||||
venv
|
||||
|
||||
19
install-melli.bat
Normal file
19
install-melli.bat
Normal file
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
REM install.bat
|
||||
REM This script sets up a Python virtual environment and installs required libraries.
|
||||
REM Make sure to run this script in the project directory.
|
||||
|
||||
REM Create Python virtual environment
|
||||
python -m venv venv
|
||||
|
||||
REM Activate the virtual environment
|
||||
call venv\Scripts\activate.bat
|
||||
|
||||
REM Upgrade pip
|
||||
pip install --upgrade pip -i https://mirror-pypi.runflare.com/simple
|
||||
|
||||
REM Install required libraries from requirements.txt
|
||||
pip install -r requirements.txt --no-cache-dir -i https://mirror-pypi.runflare.com/simple
|
||||
|
||||
echo Environment setup complete.
|
||||
pause
|
||||
@@ -1,8 +1,5 @@
|
||||
keyboard==0.13.5
|
||||
pyperclip==1.9.0
|
||||
pystray==0.19.5
|
||||
<<<<<<< HEAD
|
||||
Pillow==12.0.0
|
||||
=======
|
||||
Pillow==12.0.0
|
||||
>>>>>>> 4143eb7dfbdcc5a646f23c1fc5369779d41c4f4a
|
||||
psutil>=5.8.0
|
||||
|
||||
4
run_silent.bat
Normal file
4
run_silent.bat
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
cd /d "%~dp0"
|
||||
call venv\Scripts\activate.bat
|
||||
start "" pythonw src\main.pyw
|
||||
4
run_silent.vbs
Normal file
4
run_silent.vbs
Normal file
@@ -0,0 +1,4 @@
|
||||
Set WshShell = CreateObject("WScript.Shell")
|
||||
strPath = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
|
||||
WshShell.Run chr(34) & strPath & "\run_silent.bat" & Chr(34), 0
|
||||
Set WshShell = Nothing
|
||||
Binary file not shown.
115
src/main.pyw
115
src/main.pyw
@@ -11,8 +11,9 @@ import re
|
||||
from config import load_config, save_config, get_shortcut
|
||||
from startup import add_to_startup, remove_from_startup, is_in_startup
|
||||
import os
|
||||
import signal
|
||||
import atexit
|
||||
import sys
|
||||
import tkinter as tk
|
||||
|
||||
def convert_en_characters(input_str):
|
||||
"""
|
||||
@@ -138,6 +139,68 @@ def quit_app(icon, item):
|
||||
import os
|
||||
os._exit(0)
|
||||
|
||||
def restart_app(icon, item):
|
||||
icon.stop()
|
||||
# Unhook all keyboard hooks before restarting
|
||||
keyboard.unhook_all()
|
||||
cleanup_lock()
|
||||
import subprocess
|
||||
python = sys.executable
|
||||
script = os.path.abspath(__file__)
|
||||
subprocess.Popen([python, script])
|
||||
os._exit(0)
|
||||
|
||||
def change_shortcut_dialog():
|
||||
"""Show a dialog to capture a new keyboard shortcut."""
|
||||
root = tk.Tk()
|
||||
root.title("Change Shortcut")
|
||||
root.geometry("400x200")
|
||||
root.resizable(False, False)
|
||||
|
||||
# Center the window
|
||||
root.update_idletasks()
|
||||
x = (root.winfo_screenwidth() // 2) - (400 // 2)
|
||||
y = (root.winfo_screenheight() // 2) - (200 // 2)
|
||||
root.geometry(f"400x200+{x}+{y}")
|
||||
|
||||
captured_shortcut = {"value": None}
|
||||
|
||||
label = tk.Label(root, text="Press the key combination you want to use\nas a shortcut, then press ESC",
|
||||
font=("Arial", 12), pady=20)
|
||||
label.pack()
|
||||
|
||||
shortcut_label = tk.Label(root, text="Waiting for input...", font=("Arial", 14, "bold"), fg="blue")
|
||||
shortcut_label.pack(pady=10)
|
||||
|
||||
def capture_shortcut():
|
||||
try:
|
||||
# Unregister current hotkey before capturing new one
|
||||
keyboard.unhook_all_hotkeys()
|
||||
shortcut = keyboard.read_hotkey(suppress=False)
|
||||
captured_shortcut["value"] = shortcut
|
||||
shortcut_label.config(text=f"Captured: {shortcut}")
|
||||
root.after(1000, root.destroy)
|
||||
except Exception as e:
|
||||
shortcut_label.config(text=f"Error: {str(e)}", fg="red")
|
||||
root.after(2000, root.destroy)
|
||||
|
||||
# Start capturing in a separate thread
|
||||
capture_thread = threading.Thread(target=capture_shortcut, daemon=True)
|
||||
capture_thread.start()
|
||||
|
||||
root.mainloop()
|
||||
return captured_shortcut["value"]
|
||||
|
||||
def on_change_shortcut(icon, item):
|
||||
"""Handle shortcut change request."""
|
||||
new_shortcut = change_shortcut_dialog()
|
||||
if new_shortcut:
|
||||
config = load_config()
|
||||
config["shortcut"] = new_shortcut
|
||||
save_config(config)
|
||||
# Always restart after shortcut change attempt to ensure hotkeys are properly re-registered
|
||||
restart_app(icon, item)
|
||||
|
||||
def setup_tray(config):
|
||||
def on_toggle_lang_change(icon, item):
|
||||
config["lang_change"] = not item.checked
|
||||
@@ -153,7 +216,7 @@ def setup_tray(config):
|
||||
|
||||
image = Image.open("assets/icon.png")
|
||||
menu = pystray.Menu(
|
||||
pystray.MenuItem(f'Current Shortcut: {get_shortcut()}',lambda icon, item: None),
|
||||
pystray.MenuItem(f'Shortcut: {get_shortcut()} (click to change)', on_change_shortcut),
|
||||
pystray.MenuItem(
|
||||
'change keyboard language layout after transformation',
|
||||
on_toggle_lang_change,
|
||||
@@ -164,6 +227,7 @@ def setup_tray(config):
|
||||
on_toggle_startup,
|
||||
checked=lambda item: config["run_on_startup"]
|
||||
),
|
||||
pystray.MenuItem('Restart', restart_app),
|
||||
pystray.MenuItem('Quit', quit_app)
|
||||
)
|
||||
icon = pystray.Icon("oopswronglang", image, "OopsWrongLang", menu)
|
||||
@@ -178,22 +242,52 @@ def cleanup_lock():
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def is_process_running(pid):
|
||||
"""Check if a process with the given PID is still running."""
|
||||
try:
|
||||
import psutil
|
||||
return psutil.pid_exists(pid)
|
||||
except:
|
||||
# Fallback if psutil is not available
|
||||
try:
|
||||
os.kill(pid, 0) # Signal 0 doesn't kill, just checks if process exists
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def ensure_single_instance():
|
||||
"""Ensure only one instance of the app is running. Exit if another instance exists."""
|
||||
if os.path.exists(LOCK_FILE):
|
||||
try:
|
||||
# Read the PID from the lock file
|
||||
with open(LOCK_FILE, 'r') as f:
|
||||
pid = int(f.read().strip())
|
||||
old_pid = int(f.read().strip())
|
||||
|
||||
if pid != os.getpid():
|
||||
# Check if the process with that PID is still running
|
||||
if is_process_running(old_pid):
|
||||
# Another instance is running, show message and exit
|
||||
import ctypes
|
||||
ctypes.windll.user32.MessageBoxW(
|
||||
0,
|
||||
"Another instance of OopsWrongLang is already running.\n\nPlease close the existing instance first (check your system tray).",
|
||||
"OopsWrongLang - Already Running",
|
||||
0x40 # MB_ICONINFORMATION
|
||||
)
|
||||
os._exit(1)
|
||||
else:
|
||||
# Process is not running, remove the stale lock file
|
||||
try:
|
||||
os.kill(pid, signal.SIGTERM)
|
||||
print(f"Killed existing instance with PID {pid}")
|
||||
time.sleep(0.5)
|
||||
os.remove(LOCK_FILE)
|
||||
except OSError:
|
||||
pass
|
||||
except (ValueError, OSError):
|
||||
# Lock file exists but is invalid or unreadable, clean it up and continue
|
||||
try:
|
||||
os.remove(LOCK_FILE)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Create lock file with our PID
|
||||
with open(LOCK_FILE, 'w') as f:
|
||||
f.write(str(os.getpid()))
|
||||
|
||||
@@ -203,7 +297,12 @@ def main():
|
||||
ensure_single_instance()
|
||||
config = load_config()
|
||||
# Sync startup state just in case it was changed externally
|
||||
config["run_on_startup"] = is_in_startup()
|
||||
if is_in_startup():
|
||||
config["run_on_startup"] = True
|
||||
# Update the registry key to point to the current location (in case the app was moved)
|
||||
add_to_startup()
|
||||
else:
|
||||
config["run_on_startup"] = False
|
||||
save_config(config)
|
||||
|
||||
# Start the tray icon in a separate thread
|
||||
|
||||
@@ -2,7 +2,11 @@ import os
|
||||
import winreg
|
||||
|
||||
APP_NAME = "OopsWrongLang"
|
||||
RUN_BAT_PATH = os.path.abspath("run.bat")
|
||||
# Get the directory of the current script (src)
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# The project root is one level up
|
||||
project_root = os.path.dirname(current_dir)
|
||||
RUN_BAT_PATH = os.path.join(project_root, "run_silent.vbs")
|
||||
|
||||
def add_to_startup():
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user