-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgui_controller.py
More file actions
197 lines (170 loc) · 7.77 KB
/
gui_controller.py
File metadata and controls
197 lines (170 loc) · 7.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# gui_controller.py
"""
Controller for KeyMouse GUI.
Handles all business logic and event processing for GUI.
"""
import tkinter as tk
from tkinter import messagebox, simpledialog
import json
import logging
import os
import configparser
import shutil
from config_loader import AppConfig, get_base_path, MAPPINGS_PATH, DEFAULTS_PATH
import autostart_manager
from default_config import DefaultConfig
from typing import TYPE_CHECKING
# 避免循环导入,仅用于类型检查
if TYPE_CHECKING:
from gui import KeyMouseGUI
from app_runtime import AppRuntime
class GuiController:
# Mapping from Tkinter keysyms to pynput macro format strings
TKINTER_TO_PYNPUT_MAP = {
'Control_L': 'ctrl', 'Control_R': 'ctrl',
'Shift_L': 'shift', 'Shift_R': 'shift',
'Alt_L': 'alt', 'Alt_R': 'alt',
'Escape': 'esc',
'Return': 'enter',
'BackSpace': 'backspace',
'Caps_Lock': 'caps_lock',
'Tab': 'tab',
'space': 'space',
# Add F-keys F1-F12
**{f'F{i}': f'f{i}' for i in range(1, 13)},
}
def __init__(self, gui: 'KeyMouseGUI', config: AppConfig, app_runtime: 'AppRuntime' = None):
self.gui = gui
self.config = config
self.app_runtime = app_runtime
# autostart_manager 将在需要时作为函数使用,而不是类实例
# 缓存常用路径,避免重复构建
self._base_path = get_base_path()
self._config_path = os.path.join(self._base_path, 'config.ini')
self._key_mappings_path = os.path.join(self._base_path, 'key_mappings.json')
self._defaults_path = os.path.join(self._base_path, 'defaults.json')
def _normalize_key_string_for_pynput(self, key_string: str) -> str:
"""
Normalizes a key string from Tkinter format to pynput macro format.
Example: "Control_L+C" -> "<ctrl>+C"
"F11" -> "<f11>"
"""
if not key_string:
return ""
parts = key_string.split('+')
pynput_parts = []
for part in parts:
# Check if part is a known special key from Tkinter
normalized_part = self.TKINTER_TO_PYNPUT_MAP.get(part, part)
pynput_parts.append(normalized_part)
# Add angle brackets to special keys (multi-character keys)
formatted_parts = []
for part in pynput_parts:
# 检查:仅当长度>1且尚未被尖括号包裹时,才添加尖括号
if len(part) > 1 and not (part.startswith('<') and part.endswith('>')):
# pynput likes lowercase for special keys inside brackets
formatted_parts.append(f"<{part.lower()}>")
else:
# 保留已格式化的部分或单个字符
formatted_parts.append(part)
return "+".join(formatted_parts)
def _populate_default_mappings(self):
"""Populates key mappings file with factory defaults if it doesn't exist."""
# 从配置对象中获取 key mappings 路径
key_mappings_path = self._key_mappings_path
if not os.path.exists(key_mappings_path):
logging.info(f"'{key_mappings_path}' not found. Creating with factory defaults.")
try:
# 使用硬编码的默认配置
defaults = DefaultConfig.get_default_keybindings()
with open(key_mappings_path, 'w', encoding='utf-8') as f:
json.dump(defaults, f, indent=4)
except Exception as e:
logging.error(f"Failed to create default mappings file: {e}")
messagebox.showerror("Error", f"Failed to create default mappings file: {e}")
def get_factory_defaults(self):
"""获取出厂默认设置(现在使用硬编码配置)。"""
try:
# 直接返回硬编码的默认配置,不再依赖文件
return DefaultConfig.get_all_defaults()
except Exception as e:
logging.error(f"Error getting factory defaults: {e}")
messagebox.showerror("Error", "Could not load factory defaults from hardcoded configuration.")
return {}
def toggle_autostart(self):
"""切换自启动状态。"""
if hasattr(self.gui, 'autostart_var') and self.gui.autostart_var.get():
self.autostart_manager.enable()
else:
self.autostart_manager.disable()
def save_settings(self):
try:
# 动态构建配置路径,与 config_loader.py 中的方式一致
config_path = self._config_path
key_mappings_path = self._key_mappings_path
# 保存配置 - AppConfig 会自动处理所有保存逻辑
self.config.save_to_ini(config_path)
self.config.save_mappings_to_json(key_mappings_path)
messagebox.showinfo("成功", "设置已保存成功。")
logging.info("Settings saved successfully.")
except Exception as e:
logging.error(f"Error saving settings: {e}", exc_info=True)
messagebox.showerror("保存失败", f"保存设置时发生错误: {e}")
def restart_program(self):
logging.info("Restarting program from GUI")
try:
# 使用静态重启方法,无需创建实例
from process_manager import ProcessManager
ProcessManager.restart_application()
except Exception as e:
logging.error(f"Failed to restart program: {e}")
messagebox.showerror("重启失败", f"无法重启程序: {e}")
def save_current_as_default(self):
try:
if messagebox.askyesno("确认", "确定要将当前键位映射保存为新的出厂默认值吗?\n注意:这将修改程序的硬编码默认配置。"):
# 现在我们使用硬编码配置,这个功能提示用户需要手动修改代码
messagebox.showinfo("提示", "当前版本使用硬编码默认配置。\n如需修改默认值,请联系开发者或修改 default_config.py 文件。")
logging.info("User requested to save current settings as defaults (hardcoded version)")
except Exception as e:
logging.error(f"Error in save_current_as_default: {e}", exc_info=True)
messagebox.showerror("错误", f"操作时发生错误:{e}")
def refresh_config(self):
"""刷新配置。返回新的配置数据。"""
try:
config_path = self._config_path
# 重新创建配置对象以获取最新配置
from config_loader import AppConfig
new_config = AppConfig('config.ini')
new_config.load_from_ini(config_path)
# 更新主配置对象
self.config = new_config
# 返回配置数据供 GUI 层更新
return {
'success': True,
'config': new_config,
'message': '配置已刷新'
}
except Exception as e:
logging.error(f"Error refreshing config: {e}", exc_info=True)
return {
'success': False,
'config': None,
'message': f"无法刷新配置: {str(e)}"
}
def reset_defaults(self):
"""恢复默认设置。返回默认配置数据。"""
try:
defaults = self.get_factory_defaults()
# 返回默认配置数据供 GUI 层更新
return {
'success': True,
'defaults': defaults,
'message': '已恢复出厂默认设置(尚未保存)'
}
except Exception as e:
logging.error(f"Error resetting defaults: {e}", exc_info=True)
return {
'success': False,
'defaults': None,
'message': f'无法恢复默认设置: {str(e)}'
}