160 lines
5.5 KiB
Python
160 lines
5.5 KiB
Python
|
|
# ==============================================
|
|||
|
|
# =============== Linux系统API ===============
|
|||
|
|
# ==============================================
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import shlex
|
|||
|
|
import subprocess
|
|||
|
|
from PySide2.QtCore import QStandardPaths as Qsp
|
|||
|
|
|
|||
|
|
from umi_log import logger
|
|||
|
|
from umi_about import UmiAbout
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ==================== 快捷方式 ====================
|
|||
|
|
class _Shortcut:
|
|||
|
|
@staticmethod
|
|||
|
|
def _getPath(position): # 获取路径
|
|||
|
|
# 桌面
|
|||
|
|
if position == "desktop":
|
|||
|
|
return Qsp.writableLocation(Qsp.DesktopLocation)
|
|||
|
|
# 开始菜单
|
|||
|
|
if position == "startMenu":
|
|||
|
|
return Qsp.writableLocation(Qsp.ApplicationsLocation)
|
|||
|
|
# 开机自启 TODO
|
|||
|
|
elif position == "startup":
|
|||
|
|
raise ValueError("Linux 暂不支持自动添加开机自启。请手动设置。")
|
|||
|
|
|
|||
|
|
# 创建快捷方式,返回成功与否的字符串。position取值:
|
|||
|
|
# desktop 桌面
|
|||
|
|
# startMenu 开始菜单
|
|||
|
|
# startup 开机自启
|
|||
|
|
@staticmethod
|
|||
|
|
def createShortcut(position):
|
|||
|
|
if position == "startup": # TODO
|
|||
|
|
return "[Warning] Linux 暂不支持自动添加开机自启。请手动设置。\nAutomatically adding startup functions is not supported at this time. Please set it manually."
|
|||
|
|
try:
|
|||
|
|
lnkName = UmiAbout["name"]
|
|||
|
|
appPath = UmiAbout["app"]["path"]
|
|||
|
|
appDir = UmiAbout["app"]["dir"]
|
|||
|
|
if not appPath:
|
|||
|
|
return f"[Error] 未找到程序入口文件。请尝试手动创建快捷方式。\n[Error] Umi-OCR app path not exist. Please try creating a shortcut manually.\n\n{appPath}"
|
|||
|
|
|
|||
|
|
lnkPathBase = _Shortcut._getPath(position)
|
|||
|
|
lnkPathBase = os.path.join(lnkPathBase, lnkName)
|
|||
|
|
lnkPath = lnkPathBase + ".desktop"
|
|||
|
|
i = 1
|
|||
|
|
while os.path.exists(lnkPath): # 快捷方式已存在
|
|||
|
|
lnkPath = lnkPathBase + f" ({i}).desktop" # 添加序号
|
|||
|
|
i += 1
|
|||
|
|
except Exception as e:
|
|||
|
|
return f"[Error] 无法获取应用信息。\n[Error] Unable to obtain application information.\n\n{e}"
|
|||
|
|
|
|||
|
|
# 快捷方式 文件内容
|
|||
|
|
desktop_entry = f"""
|
|||
|
|
[Desktop Entry]
|
|||
|
|
Version={UmiAbout["version"]["string"]}
|
|||
|
|
Type=Application
|
|||
|
|
Name={lnkName}
|
|||
|
|
Exec={appPath}
|
|||
|
|
Path={appDir}
|
|||
|
|
Icon={appDir}/UmiOCR-data/qt_res/images/icons/umiocr.ico
|
|||
|
|
Terminal=false
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
with open(lnkPath, "w") as f:
|
|||
|
|
f.write(desktop_entry)
|
|||
|
|
os.chmod(lnkPath, 0o755) # 赋予执行权限
|
|||
|
|
logger.info(f"创建快捷方式: {lnkPath}")
|
|||
|
|
return "[Success]"
|
|||
|
|
except Exception as e:
|
|||
|
|
return f"[Error] 创建快捷方式失败。\n[Error] Failed to create shortcut.\n {lnkPath}: {e}"
|
|||
|
|
|
|||
|
|
# 删除快捷方式,返回删除文件的个数
|
|||
|
|
@staticmethod
|
|||
|
|
def deleteShortcut(position):
|
|||
|
|
try:
|
|||
|
|
appName = UmiAbout["name"]
|
|||
|
|
lnkDir = _Shortcut._getPath(position)
|
|||
|
|
except Exception:
|
|||
|
|
logger.error("无法获取应用信息", exc_info=True, stack_info=True)
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
num = 0
|
|||
|
|
for fileName in os.listdir(lnkDir):
|
|||
|
|
try:
|
|||
|
|
lnkPath = os.path.join(lnkDir, fileName)
|
|||
|
|
if not os.path.isfile(lnkPath): # 排除非文件
|
|||
|
|
continue
|
|||
|
|
if fileName.startswith(appName) and fileName.endswith(".desktop"):
|
|||
|
|
os.remove(lnkPath)
|
|||
|
|
num += 1
|
|||
|
|
logger.info(f"删除快捷方式: {lnkPath}")
|
|||
|
|
except Exception:
|
|||
|
|
logger.error(
|
|||
|
|
f"删除快捷方式失败。 lnkPath: {lnkPath}",
|
|||
|
|
exc_info=True,
|
|||
|
|
stack_info=True,
|
|||
|
|
)
|
|||
|
|
continue
|
|||
|
|
return num
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ==================== 硬件控制 ====================
|
|||
|
|
class _HardwareCtrl:
|
|||
|
|
# 关机
|
|||
|
|
@staticmethod
|
|||
|
|
def shutdown():
|
|||
|
|
# TODO: sudo权限?
|
|||
|
|
os.system("sudo shutdown -h now")
|
|||
|
|
|
|||
|
|
# 休眠
|
|||
|
|
@staticmethod
|
|||
|
|
def hibernate():
|
|||
|
|
os.system("sudo systemctl hibernate")
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ==================== 对外接口 ====================
|
|||
|
|
class Api:
|
|||
|
|
# 快捷方式。接口: createShortcut deleteShortcut
|
|||
|
|
# 参数:快捷方式位置, desktop startMenu startup
|
|||
|
|
Shortcut = _Shortcut()
|
|||
|
|
|
|||
|
|
# 硬件控制。接口: shutdown hibernate
|
|||
|
|
HardwareCtrl = _HardwareCtrl()
|
|||
|
|
|
|||
|
|
# TODO: 根据系统及硬件,判断最适合的渲染器类型
|
|||
|
|
@staticmethod
|
|||
|
|
def getOpenGLUse():
|
|||
|
|
return "AA_UseOpenGLES" # 默认使用GLES。
|
|||
|
|
# return "AA_UseSoftwareOpenGL" # 如果不兼容?则使用软渲染
|
|||
|
|
|
|||
|
|
# 键值转键名
|
|||
|
|
@staticmethod
|
|||
|
|
def getKeyName(key):
|
|||
|
|
# 传入 pynput 按键事件对象,返回键名字符串
|
|||
|
|
if not isinstance(key, str):
|
|||
|
|
key = str(key)
|
|||
|
|
if not key: # 错误,未获取键值
|
|||
|
|
return "unknown"
|
|||
|
|
if key.startswith("'") and key.endswith("'"): # 去除自带引号
|
|||
|
|
key = key[1:-1]
|
|||
|
|
if key.startswith("Key."): # 修饰建
|
|||
|
|
key = key[4:]
|
|||
|
|
if not key: # 再检查一次
|
|||
|
|
return "unknown"
|
|||
|
|
return key
|
|||
|
|
|
|||
|
|
# 让系统运行一个程序,不堵塞当前进程
|
|||
|
|
@staticmethod
|
|||
|
|
def runNewProcess(path, args=""):
|
|||
|
|
# TODO: 测试、完善
|
|||
|
|
command_line = [path] + shlex.split(args)
|
|||
|
|
subprocess.Popen(command_line)
|
|||
|
|
|
|||
|
|
# 用系统默认应用打开一个文件或目录,不堵塞当前进程
|
|||
|
|
@staticmethod
|
|||
|
|
def startfile(path):
|
|||
|
|
os.startfile(path)
|