{"id":3621,"date":"2025-07-30T21:30:31","date_gmt":"2025-07-30T13:30:31","guid":{"rendered":"https:\/\/blog.kangyue.pro\/?p=3621"},"modified":"2025-08-15T11:12:14","modified_gmt":"2025-08-15T03:12:14","slug":"%e4%b8%80%e4%b8%aa%e7%94%b1%e5%85%a8%e6%96%b0%e7%9a%84%e6%8f%90%e7%a4%ba%e9%9f%b3%e5%b7%a5%e5%85%b7%ef%bc%88python%ef%bc%89","status":"publish","type":"post","link":"https:\/\/blog.kangyue.pro\/?p=3621","title":{"rendered":"\u4e00\u6b3e\u667a\u80fd\u7684\u63d0\u793a\u97f3\u5de5\u5177\uff08Python\uff09"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\">\u5de5\u5177\u4ecb\u7ecd<\/h1>\n\n\n\n<p>\u8fd9\u4e2a\u5de5\u5177\u662f\u4e00\u4e2a\u57fa\u4e8e Python \u548c Tkinter \u5f00\u53d1\u7684<strong>\u667a\u80fd\u54cd\u94c3\u5668<\/strong>\uff0c\u7528\u4e8e\u5728\u7279\u5b9a\u6761\u4ef6\u4e0b\u89e6\u53d1\u7cfb\u7edf\u63d0\u793a\u97f3\uff0c\u63d0\u9192\u7528\u6237\u6ce8\u610f\u3002\u5de5\u5177\u63d0\u4f9b\u4e09\u79cd\u68c0\u6d4b\u6a21\u5f0f\uff0c\u754c\u9762\u7b80\u6d01\uff0c\u652f\u6301\u4e2d\u6587\uff0c\u652f\u6301\u8de8\u5e73\u53f0\uff08Windows \u548c\u975e Windows \u7cfb\u7edf\uff09\uff0c\u5e76\u5177\u6709\u4ee5\u4e0b\u529f\u80fd\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u56fa\u5b9a\u65f6\u95f4\u54cd\u94c3<\/strong>\uff1a\u6bcf\u9694\u6307\u5b9a\u5206\u949f\u6570\u54cd\u94c3\uff0c\u9002\u5408\u5b9a\u65f6\u63d0\u9192\uff08\u5982\u5de5\u4f5c\u4f11\u606f\uff09\u3002<\/li>\n\n\n\n<li><strong>\u533a\u57df\u989c\u8272\u68c0\u6d4b<\/strong>\uff1a\u76d1\u63a7\u5c4f\u5e55\u6307\u5b9a\u533a\u57df\u7684\u4eae\u5ea6\uff0c\u5f53\u533a\u57df\u6301\u7eed\u53d8\u6697\uff08\u5982\u89c6\u9891\u64ad\u653e\u5668\u6682\u505c\u6216\u9ed1\u5c4f\uff09\u8d85\u8fc7\u8bbe\u5b9a\u65f6\u95f4\uff0c\u6216\u8fbe\u5230\u6700\u5927\u7b49\u5f85\u65f6\u95f4\u65f6\u54cd\u94c3\u3002<\/li>\n\n\n\n<li><strong>\u7f51\u901f\u68c0\u6d4b<\/strong>\uff1a\u68c0\u6d4b\u672c\u5730\u7f51\u5361\u4e0b\u8f7d\u901f\u5ea6\uff0c\u5f53\u901f\u5ea6\u6301\u7eed\u4f4e\u4e8e\u8bbe\u5b9a\u9608\u503c\uff08\u5982 50 KB\/s\uff09\u65f6\u54cd\u94c3\uff0c\u9002\u5408\u76d1\u63a7\u7f51\u7edc\u4efb\u52a1\u3002<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">\u4e3b\u8981\u7279\u70b9<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u54cd\u94c3\u6a21\u5f0f<\/strong>\uff1a\u652f\u6301\u201c\u54cd\u4e00\u4e0b\u201d\u6216\u201c\u6301\u7eed\u54cd\u94c3\u201d\uff08\u53ef\u8bbe\u7f6e\u6700\u957f\u6301\u7eed\u65f6\u95f4\uff09\u3002<\/li>\n\n\n\n<li><strong>\u91cd\u7f6e\u65b9\u5f0f<\/strong>\uff1a\u53ef\u9009\u62e9\u54cd\u94c3\u540e\u901a\u8fc7\u9f20\u6807\/\u952e\u76d8\u64cd\u4f5c\u3001\u7a97\u53e3\u805a\u7126\u6216\u4e0d\u91cd\u7f6e\u6765\u8fdb\u5165\u4e0b\u4e00\u68c0\u6d4b\u5468\u671f\uff08\u533a\u57df\u989c\u8272\u68c0\u6d4b\u59cb\u7ec8\u9700\u7528\u6237\u64cd\u4f5c\u91cd\u7f6e\uff09\u3002<\/li>\n\n\n\n<li><strong>\u7528\u6237\u6d3b\u52a8\u68c0\u6d4b<\/strong>\uff1a\u4ec5\u5728\u54cd\u94c3\u671f\u95f4\u68c0\u6d4b\u9f20\u6807\/\u952e\u76d8\u64cd\u4f5c\uff0c\u907f\u514d\u6b63\u5e38\u68c0\u6d4b\u65f6\u88ab\u6253\u65ad\u3002<\/li>\n\n\n\n<li><strong>\u914d\u7f6e\u4fdd\u5b58<\/strong>\uff1a\u6240\u6709\u8bbe\u7f6e\uff08\u5982\u533a\u57df\u5750\u6807\u3001\u65f6\u95f4\u3001\u7f51\u901f\u9608\u503c\u3001\u97f3\u91cf\u3001\u6a21\u5f0f\uff09\u81ea\u52a8\u4fdd\u5b58\u5230 bell_app_config.json\uff0c\u4e0b\u6b21\u542f\u52a8\u65f6\u81ea\u52a8\u52a0\u8f7d\u3002<\/li>\n\n\n\n<li><strong>\u97f3\u91cf\u63a7\u5236<\/strong>\uff1a\u652f\u6301\u8c03\u6574\u7cfb\u7edf\u97f3\u91cf\uff08Windows \u4e13\u7528\uff09\u3002<\/li>\n\n\n\n<li><strong>\u533a\u57df\u9009\u62e9<\/strong>\uff1a\u901a\u8fc7\u62d6\u62fd\u9009\u62e9\u5c4f\u5e55\u76d1\u63a7\u533a\u57df\uff0c\u76f4\u89c2\u6613\u7528\u3002<\/li>\n\n\n\n<li><strong>\u9519\u8bef\u5904\u7406<\/strong>\uff1a\u652f\u6301\u914d\u7f6e\u6587\u4ef6\u7684\u9519\u8bef\u6062\u590d\uff0c\u4f7f\u7528\u9ed8\u8ba4\u503c\uff0c\u786e\u4fdd\u7a0b\u5e8f\u7a33\u5b9a\u6027\u3002<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u4f7f\u7528\u573a\u666f<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u5de5\u4f5c\u63d0\u9192<\/strong>\uff1a\u5b9a\u65f6\u63d0\u9192\u4f11\u606f\u6216\u4efb\u52a1\u5207\u6362\u3002<\/li>\n\n\n\n<li><strong>\u89c6\u9891\u76d1\u63a7<\/strong>\uff1a\u68c0\u6d4b\u89c6\u9891\u64ad\u653e\u5668\u662f\u5426\u6682\u505c\uff08\u9ed1\u5c4f\uff09\u3002<\/li>\n\n\n\n<li><strong>\u7f51\u7edc\u76d1\u63a7<\/strong>\uff1a\u63d0\u9192\u4e0b\u8f7d\u4efb\u52a1\u901f\u5ea6\u8fc7\u4f4e\u6216\u5b8c\u6210\u3002<\/li>\n<\/ul>\n\n\n\n<p>\u5de5\u5177\u754c\u9762\u901a\u8fc7\u9009\u9879\u5361\u7ec4\u7ec7\uff0c\u64cd\u4f5c\u7b80\u5355\uff0c\u652f\u6301\u5b9e\u65f6\u72b6\u6001\u663e\u793a\uff08\u5982\u5012\u8ba1\u65f6\u3001\u7f51\u901f\uff09\uff0c\u9002\u5408\u9700\u8981\u81ea\u52a8\u5316\u63d0\u9192\u7684\u7528\u6237\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">\u8fd0\u884c\u73af\u5883\u8981\u6c42<\/h1>\n\n\n\n<h3 class=\"wp-block-heading\">\u64cd\u4f5c\u7cfb\u7edf<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Windows10\u621611<\/li>\n\n\n\n<li>python 3.12\u62163.13\uff08py\u6587\u4ef6\uff0cexe\u65e0\u6b64\u8981\u6c42\uff09<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u5e93<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pip install playsound pynput psutil Pillow pycaw<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"668\" height=\"687\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-31.png\" alt=\"\" class=\"wp-image-3717\"\/><\/figure>\n\n\n\n<p>\u5982\u82e5\u8fd0\u884cpy\u6587\u4ef6\u95ea\u9000\uff0c\u53ef\u518d\u5c1d\u8bd5\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pip install pynput psutil Pillow pycaw<\/li>\n<\/ul>\n\n\n\n<p><em>\uff08\u53ef\u80fd\u9700\u8981\u5173\u95ed\u672c\u5730\u4ee3\u7406\u540e\u8fd0\u884c\u4ee5\u4e0a\u4e24\u6761\u547d\u4ee4\uff09<\/em><\/p>\n\n\n\n<h1 class=\"wp-block-heading has-text-align-center\">V7.4<\/h1>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"302\" height=\"213\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-29.png\" alt=\"\" class=\"wp-image-3632\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"583\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-30.png\" alt=\"\" class=\"wp-image-3633\"\/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">\u4ee3\u7801<\/h1>\n\n\n\t\t<div class='wp-block-bch-code-highlight  align' id='bhcCodeHighlight-1c55d6fa-a' data-attributes='{&quot;cId&quot;:&quot;1c55d6fa-a&quot;,&quot;language&quot;:&quot;python&quot;,&quot;code&quot;:&quot;# -*- coding: utf-8 -*-\\nimport sys\\nimport os\\nimport platform\\nimport ctypes\\nimport traceback\\nimport json\\nimport threading\\nimport time\\nimport tkinter as tk\\nfrom tkinter import messagebox, ttk\\nfrom PIL import ImageGrab, ImageStat\\nfrom pynput import mouse, keyboard\\n\\ntry:\\n    import psutil\\nexcept ImportError:\\n    messagebox.showerror(\\&quot;\\u7f3a\\u5c11\\u4f9d\\u8d56\\&quot;, \\&quot;\\u8bf7\\u5148\\u5b89\\u88c5 &#039;psutil&#039; \\u5e93\\uff1a\\\\npip install psutil\\&quot;)\\n    sys.exit()\\n\\nif platform.system() == &#039;Windows&#039;:\\n    import winsound\\n    from ctypes import POINTER, cast\\n    from comtypes import CLSCTX_ALL, CoInitialize\\n    from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume\\n\\n# ----------------- Constants -----------------\\nDEFAULT_VOLUME = 100\\nDEFAULT_REGION_LEFT = 100\\nDEFAULT_REGION_TOP = 100\\nDEFAULT_REGION_RIGHT = 400\\nDEFAULT_REGION_BOTTOM = 300\\nDEFAULT_DARK_THRESHOLD = 30\\nDEFAULT_DARK_DURATION_SEC = 20\\nDEFAULT_MAX_WAIT_MINUTES = 10\\nDEFAULT_TIMER_MINUTES = 5\\nDEFAULT_TIMER_TIMES = 90\\nDEFAULT_BELL_MODE = \\&quot;1\\&quot;\\nDEFAULT_SPEED_THRESHOLD_KB = 50\\nDEFAULT_LOW_SPEED_DURATION_SEC = 20\\nDEFAULT_CHECK_INTERVAL_SEC = 2\\nDEFAULT_RESET_MODE = \\&quot;mouse_move\\&quot;\\nDEFAULT_CONTINUOUS_BELL_DURATION = 5\\nDEFAULT_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 12)\\nSTATUS_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 12)\\nCOUNTDOWN_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 14)\\n\\n# ----------------- AudioUtils -----------------\\ndef set_system_volume(vol_percent):\\n    if platform.system() != &#039;Windows&#039;:\\n        return\\n    try:\\n        CoInitialize()\\n        devices = AudioUtilities.GetSpeakers()\\n        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)\\n        volume = cast(interface, POINTER(IAudioEndpointVolume))\\n        vol = float(vol_percent) \\\/ 100.0\\n        volume.SetMasterVolumeLevelScalar(vol, None)\\n    except Exception as e:\\n        print(f\\&quot;[\\u97f3\\u91cf\\u8c03\\u8282\\u5931\\u8d25] {e}\\&quot;)\\n\\ndef play_bell_sound():\\n    if platform.system() == &#039;Windows&#039;:\\n        try:\\n            winsound.Beep(800, 300)\\n        except Exception as e:\\n            print(f\\&quot;[\\u64ad\\u653e\\u63d0\\u793a\\u97f3\\u5931\\u8d25] {e}\\&quot;)\\n    else:\\n        os.system(&#039;echo -e \\&quot;\\\\\\\\a\\&quot;&#039;)\\n\\n# ----------------- RegionSelector -----------------\\nclass RegionSelector(tk.Toplevel):\\n    def __init__(self, master, callback):\\n        super().__init__(master)\\n        self.callback = callback\\n        self.start_x = None\\n        self.start_y = None\\n        self.rect = None\\n        self.geometry(f\\&quot;{self.winfo_screenwidth()}x{self.winfo_screenheight()}+0+0\\&quot;)\\n        self.overrideredirect(True)\\n        self.attributes(&#039;-alpha&#039;, 0.3)\\n        self.attributes(&#039;-topmost&#039;, True)\\n        self.config(bg=&#039;black&#039;)\\n        self.canvas = tk.Canvas(self, cursor=\\&quot;cross\\&quot;, bg=&#039;black&#039;)\\n        self.canvas.pack(fill=tk.BOTH, expand=True)\\n        self.canvas.bind(\\&quot;&lt;ButtonPress-1&gt;\\&quot;, self.on_button_press)\\n        self.canvas.bind(\\&quot;&lt;B1-Motion&gt;\\&quot;, self.on_mouse_move)\\n        self.canvas.bind(\\&quot;&lt;ButtonRelease-1&gt;\\&quot;, self.on_button_release)\\n\\n    def on_button_press(self, event):\\n        self.start_x = self.canvas.canvasx(event.x)\\n        self.start_y = self.canvas.canvasy(event.y)\\n        if self.rect:\\n            self.canvas.delete(self.rect)\\n        self.rect = self.canvas.create_rectangle(self.start_x, self.start_y,\\n                                                self.start_x, self.start_y,\\n                                                outline=&#039;red&#039;, width=2)\\n\\n    def on_mouse_move(self, event):\\n        cur_x = self.canvas.canvasx(event.x)\\n        cur_y = self.canvas.canvasy(event.y)\\n        self.canvas.coords(self.rect, self.start_x, self.start_y, cur_x, cur_y)\\n\\n    def on_button_release(self, event):\\n        end_x = self.canvas.canvasx(event.x)\\n        end_y = self.canvas.canvasy(event.y)\\n        left = int(min(self.start_x, end_x))\\n        top = int(min(self.start_y, end_y))\\n        right = int(max(self.start_x, end_x))\\n        bottom = int(max(self.start_y, end_y))\\n        self.callback(left, top, right, bottom)\\n        self.destroy()\\n\\n# ----------------- ConfigManager -----------------\\nclass ConfigManager:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.config_file = \\&quot;bell_app_config.json\\&quot;\\n\\n    def save_config(self):\\n        config = {\\n            \\&quot;tab_selected\\&quot;: self.app.notebook.index(self.app.notebook.select()),\\n            \\&quot;region_left\\&quot;: self.app.left_var.get(),\\n            \\&quot;region_top\\&quot;: self.app.top_var.get(),\\n            \\&quot;region_right\\&quot;: self.app.right_var.get(),\\n            \\&quot;region_bottom\\&quot;: self.app.bottom_var.get(),\\n            \\&quot;dark_threshold\\&quot;: self.app.dark_threshold_var.get(),\\n            \\&quot;dark_duration_sec\\&quot;: self.app.dark_duration_sec_var.get(),\\n            \\&quot;max_wait_minutes\\&quot;: self.app.max_wait_minutes_var.get(),\\n            \\&quot;timer_minutes\\&quot;: self.app.minutes_var.get(),\\n            \\&quot;timer_times\\&quot;: self.app.times_var.get(),\\n            \\&quot;bell_mode\\&quot;: self.app.mode_var.get(),\\n            \\&quot;speed_threshold_kb\\&quot;: self.app.speed_threshold_kb_var.get(),\\n            \\&quot;low_speed_duration_sec\\&quot;: self.app.low_speed_duration_sec_var.get(),\\n            \\&quot;check_interval_sec\\&quot;: self.app.check_interval_sec_var.get(),\\n            \\&quot;volume\\&quot;: self.app.volume_var.get(),\\n            \\&quot;continuous_bell_duration\\&quot;: self.app.continuous_bell_duration_var.get(),\\n            \\&quot;reset_mode\\&quot;: self.app.reset_mode_var.get(),\\n            \\&quot;is_mini_mode\\&quot;: self.app.is_mini_mode.get()\\n        }\\n        try:\\n            with open(self.config_file, &#039;w&#039;, encoding=&#039;utf-8&#039;) as f:\\n                json.dump(config, f, ensure_ascii=False, indent=2)\\n        except Exception as e:\\n            print(f\\&quot;[\\u4fdd\\u5b58\\u914d\\u7f6e\\u5931\\u8d25] {e}\\&quot;)\\n\\n    def load_config(self):\\n        if not os.path.exists(self.config_file):\\n            print(\\&quot;\\u914d\\u7f6e\\u6587\\u4ef6\\u4e0d\\u5b58\\u5728\\uff0c\\u4f7f\\u7528\\u9ed8\\u8ba4\\u8bbe\\u7f6e\\&quot;)\\n            return\\n        try:\\n            with open(self.config_file, &#039;r&#039;, encoding=&#039;utf-8&#039;) as f:\\n                config = json.load(f)\\n                self.app.notebook.select(config.get(\\&quot;tab_selected\\&quot;, 2))\\n                self.app.left_var.set(config.get(\\&quot;region_left\\&quot;, str(DEFAULT_REGION_LEFT)))\\n                self.app.top_var.set(config.get(\\&quot;region_top\\&quot;, str(DEFAULT_REGION_TOP)))\\n                self.app.right_var.set(config.get(\\&quot;region_right\\&quot;, str(DEFAULT_REGION_RIGHT)))\\n                self.app.bottom_var.set(config.get(\\&quot;region_bottom\\&quot;, str(DEFAULT_REGION_BOTTOM)))\\n                self.app.dark_threshold_var.set(config.get(\\&quot;dark_threshold\\&quot;, str(DEFAULT_DARK_THRESHOLD)))\\n                self.app.dark_duration_sec_var.set(config.get(\\&quot;dark_duration_sec\\&quot;, str(DEFAULT_DARK_DURATION_SEC)))\\n                self.app.max_wait_minutes_var.set(config.get(\\&quot;max_wait_minutes\\&quot;, str(DEFAULT_MAX_WAIT_MINUTES)))\\n                self.app.minutes_var.set(config.get(\\&quot;timer_minutes\\&quot;, str(DEFAULT_TIMER_MINUTES)))\\n                self.app.times_var.set(config.get(\\&quot;timer_times\\&quot;, str(DEFAULT_TIMER_TIMES)))\\n                self.app.mode_var.set(config.get(\\&quot;bell_mode\\&quot;, DEFAULT_BELL_MODE))\\n                self.app.continuous_bell_duration_var.set(config.get(\\&quot;continuous_bell_duration\\&quot;, str(DEFAULT_CONTINUOUS_BELL_DURATION)))\\n                self.app.speed_threshold_kb_var.set(config.get(\\&quot;speed_threshold_kb\\&quot;, str(DEFAULT_SPEED_THRESHOLD_KB)))\\n                self.app.low_speed_duration_sec_var.set(config.get(\\&quot;low_speed_duration_sec\\&quot;, str(DEFAULT_LOW_SPEED_DURATION_SEC)))\\n                self.app.check_interval_sec_var.set(config.get(\\&quot;check_interval_sec\\&quot;, str(DEFAULT_CHECK_INTERVAL_SEC)))\\n                self.app.volume_var.set(config.get(\\&quot;volume\\&quot;, DEFAULT_VOLUME))\\n                self.app.reset_mode_var.set(config.get(\\&quot;reset_mode\\&quot;, DEFAULT_RESET_MODE))\\n                self.app.is_mini_mode.set(config.get(\\&quot;is_mini_mode\\&quot;, False))\\n                self.app.region_status_label.config(text=f\\&quot;\\u5df2\\u52a0\\u8f7d\\u4e0a\\u6b21\\u533a\\u57df\\uff1a({self.app.left_var.get()},{self.app.top_var.get()},{self.app.right_var.get()},{self.app.bottom_var.get()})\\&quot;)\\n                if self.app.is_mini_mode.get():\\n                    self.app.toggle_window_mode()\\n        except json.JSONDecodeError as e:\\n            print(f\\&quot;[\\u914d\\u7f6e\\u6587\\u4ef6\\u683c\\u5f0f\\u9519\\u8bef] {e}\\&quot;)\\n            messagebox.showwarning(\\&quot;\\u52a0\\u8f7d\\u914d\\u7f6e\\&quot;, \\&quot;\\u914d\\u7f6e\\u6587\\u4ef6\\u683c\\u5f0f\\u9519\\u8bef\\uff0c\\u5c06\\u4f7f\\u7528\\u9ed8\\u8ba4\\u8bbe\\u7f6e\\u3002\\&quot;)\\n        except Exception as e:\\n            print(f\\&quot;[\\u52a0\\u8f7d\\u914d\\u7f6e\\u5931\\u8d25] {e}\\&quot;)\\n            messagebox.showwarning(\\&quot;\\u52a0\\u8f7d\\u914d\\u7f6e\\&quot;, f\\&quot;\\u52a0\\u8f7d\\u5386\\u53f2\\u914d\\u7f6e\\u5931\\u8d25\\uff0c\\u5c06\\u4f7f\\u7528\\u9ed8\\u8ba4\\u8bbe\\u7f6e\\u3002\\\\n\\u9519\\u8bef\\uff1a{e}\\&quot;)\\n\\n# ----------------- Detector Classes -----------------\\nclass RegionColorDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.was_dark_previously = False\\n        self.dark_start_time = None\\n        self.countdown_start_time = 0\\n        self.last_brightness = None\\n        self.last_check_time = 0\\n\\n    def reset_state(self):\\n        self.was_dark_previously = False\\n        self.dark_start_time = None\\n        self.countdown_start_time = 0\\n        self.last_brightness = None\\n        self.last_check_time = 0\\n\\n    def get_region_brightness(self):\\n        if self.last_brightness is not None and time.time() - self.last_check_time &lt; 1:\\n            return self.last_brightness\\n        try:\\n            bbox = (\\n                int(self.app.left_var.get()),\\n                int(self.app.top_var.get()),\\n                int(self.app.right_var.get()),\\n                int(self.app.bottom_var.get())\\n            )\\n            current_img = ImageGrab.grab(bbox=bbox).convert(&#039;L&#039;)\\n            mean_brightness = ImageStat.Stat(current_img).mean[0]\\n            self.last_brightness = mean_brightness\\n            self.last_check_time = time.time()\\n            return mean_brightness\\n        except Exception as e:\\n            print(f\\&quot;[\\u622a\\u56fe\\u68c0\\u6d4b\\u5f02\\u5e38] {e}\\&quot;)\\n            self.app.root.after(0, lambda exc=e: self.app.region_status_label.config(text=f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u5f02\\u5e38\\uff1a{exc}\\&quot;, fg=\\&quot;red\\&quot;))\\n            return -1\\n\\n    def check_condition(self):\\n        should_ring = False\\n        status_message = \\&quot;\\&quot;\\n        dark_threshold = int(self.app.dark_threshold_var.get())\\n        dark_duration_sec = int(self.app.dark_duration_sec_var.get())\\n        max_wait_seconds = int(float(self.app.max_wait_minutes_var.get()) * 60)\\n        current_time = time.time()\\n        elapsed_max_wait_time = int(current_time - self.app.start_cycle_time)\\n\\n        if elapsed_max_wait_time &gt;= max_wait_seconds:\\n            should_ring = True\\n            status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u8d85\\u65f6\\uff0c\\u5f3a\\u5236\\u54cd\\u94c3\\&quot;\\n            self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;red\\&quot;))\\n            return should_ring, status_message\\n\\n        current_brightness = self.get_region_brightness()\\n        is_current_dark = (current_brightness != -1 and current_brightness &lt;= dark_threshold)\\n\\n        if is_current_dark:\\n            if not self.was_dark_previously:\\n                self.dark_start_time = current_time\\n                status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u68c0\\u6d4b\\u5230\\u533a\\u57df\\u53d8\\u6697\\uff0c\\u5f00\\u59cb\\u8ba1\\u65f6...\\&quot;\\n                self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n            else:\\n                if self.dark_start_time is not None and (current_time - self.dark_start_time) &gt;= dark_duration_sec:\\n                    should_ring = True\\n                    status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u6697\\u8272\\u8fbe\\u5230\\u9608\\u503c\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n                    self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;green\\&quot;))\\n                else:\\n                    duration = 0 if self.dark_start_time is None else (current_time - self.dark_start_time)\\n                    status_message = f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u6697\\u8272\\u4e2d {duration:.1f} \\\/ {dark_duration_sec} \\u79d2\\&quot;\\n                    self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n        else:\\n            self.dark_start_time = None\\n            status_message = f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u533a\\u57df\\u6b63\\u5e38 (\\u5f53\\u524d\\u4eae\\u5ea6 {current_brightness:.2f} \\\/ \\u9608\\u503c {dark_threshold})\\&quot;\\n            self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;black\\&quot;))\\n        \\n        self.was_dark_previously = is_current_dark\\n        self.countdown_start_time = current_time\\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        max_wait_seconds = int(float(self.app.max_wait_minutes_var.get()) * 60)\\n        remaining_time = max_wait_seconds - int(time.time() - self.app.start_cycle_time)\\n        mins, secs = divmod(max(0, remaining_time), 60)\\n        return f\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a{mins:02d}:{secs:02d}\\&quot;\\n\\nclass NetworkSpeedDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self._last_net_bytes_recv = 0\\n        self._last_net_timestamp = 0\\n        self.low_speed_start_time = None\\n        self.is_low_speed_currently = False\\n        self.was_low_speed_previously = False\\n        self.awaiting_significant_traffic = True\\n        self.countdown_start_time = 0\\n\\n    def reset_state(self):\\n        self._last_net_bytes_recv = 0\\n        self._last_net_timestamp = 0\\n        self.low_speed_start_time = None\\n        self.is_low_speed_currently = False\\n        self.was_low_speed_previously = False\\n        self.awaiting_significant_traffic = True\\n        self.countdown_start_time = 0\\n\\n    def get_network_speed(self):\\n        try:\\n            current_counters = psutil.net_io_counters()\\n            current_time = time.time()\\n            if self._last_net_timestamp == 0:\\n                self._last_net_bytes_recv = current_counters.bytes_recv\\n                self._last_net_timestamp = current_time\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u521d\\u59cb\\u5316\\u4e2d...\\&quot;, fg=\\&quot;blue\\&quot;))\\n                self.app.root.after(0, lambda: self.app.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n                return 0.0\\n            time_diff = current_time - self._last_net_timestamp\\n            if time_diff &lt;= 0:\\n                return 0.0\\n            recv_diff = current_counters.bytes_recv - self._last_net_bytes_recv\\n            self._last_net_bytes_recv = current_counters.bytes_recv\\n            self._last_net_timestamp = current_time\\n            speed_kbps = (recv_diff \\\/ time_diff) \\\/ 1024\\n            return speed_kbps\\n        except Exception as e:\\n            print(f\\&quot;[\\u7f51\\u901f\\u68c0\\u6d4b\\u5f02\\u5e38] {e}\\&quot;)\\n            self.app.root.after(0, lambda exc=e: self.app.network_status_label.config(text=f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u5f02\\u5e38\\uff1a{exc}\\&quot;, fg=\\&quot;red\\&quot;))\\n            self.app.root.after(0, lambda: self.app.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a\\u68c0\\u6d4b\\u5931\\u8d25\\&quot;, fg=\\&quot;red\\&quot;))\\n            self.app.root.after(0, lambda: self.app.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a\\u68c0\\u6d4b\\u5931\\u8d25\\&quot;, fg=\\&quot;red\\&quot;))\\n            return -1.0\\n\\n    def check_condition(self):\\n        should_ring = False\\n        status_message = \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u4e2d...\\&quot;\\n        speed_threshold_kb = float(self.app.speed_threshold_kb_var.get())\\n        low_speed_duration_sec = int(self.app.low_speed_duration_sec_var.get())\\n        current_speed = self.get_network_speed()\\n\\n        if current_speed == -1.0:\\n            status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u68c0\\u6d4b\\u5931\\u8d25\\uff0c\\u91cd\\u8bd5\\u4e2d...\\&quot;\\n            self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;red\\&quot;))\\n            self.app.root.after(0, lambda: self.app.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n            self.app.root.after(0, lambda: self.app.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n            return False, status_message\\n\\n        self.app.root.after(0, lambda s=current_speed: self.app.current_speed_label.config(text=f\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a{s:.2f} KB\\\/S\\&quot;))\\n        self.app.root.after(0, lambda s=current_speed: self.app.mini_speed_label.config(text=f\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a{s:.2f} KB\\\/S\\&quot;))\\n        self.is_low_speed_currently = (current_speed &lt; speed_threshold_kb)\\n\\n        if self.awaiting_significant_traffic:\\n            if current_speed &gt;= speed_threshold_kb * 2 and current_speed &gt; 0:\\n                self.awaiting_significant_traffic = False\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u5df2\\u68c0\\u6d4b\\u5230\\u6d41\\u91cf\\uff0c\\u5f00\\u59cb\\u76d1\\u6d4b...\\&quot;, fg=\\&quot;blue\\&quot;))\\n                return False, status_message\\n            else:\\n                status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7b49\\u5f85\\u6709\\u660e\\u663e\\u6d41\\u91cf\\u65f6\\u5f00\\u59cb\\u76d1\\u6d4b...\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;gray\\&quot;))\\n                return False, status_message\\n\\n        if self.is_low_speed_currently:\\n            if not self.was_low_speed_previously:\\n                self.low_speed_start_time = time.time()\\n                status_message = f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u8fdb\\u5165\\u4f4e\\u901f\\u72b6\\u6001\\uff0c\\u6301\\u7eed {0:.1f} \\\/ {low_speed_duration_sec} \\u79d2\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n            else:\\n                duration = time.time() - self.low_speed_start_time\\n                status_message = f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u4f4e\\u901f\\u4e2d {duration:.1f} \\\/ {low_speed_duration_sec} \\u79d2\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n                if duration &gt;= low_speed_duration_sec:\\n                    should_ring = True\\n                    status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7f51\\u901f\\u6301\\u7eed\\u4f4e\\u4e8e\\u9608\\u503c\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n                    self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;green\\&quot;))\\n        else:\\n            self.low_speed_start_time = None\\n            status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7f51\\u901f\\u6b63\\u5e38\\&quot;\\n            self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;black\\&quot;))\\n        \\n        self.was_low_speed_previously = self.is_low_speed_currently\\n        self.countdown_start_time = time.time()\\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        return \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u4e2d...\\&quot;\\n\\nclass TimerDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.countdown_start_time = 0\\n\\n    def reset_state(self):\\n        self.countdown_start_time = 0\\n\\n    def check_condition(self):\\n        should_ring = False\\n        status_message = \\&quot;\\&quot;\\n        interval_seconds = int(float(self.app.minutes_var.get()) * 60)\\n        current_time = time.time()\\n        \\n        if self.countdown_start_time == 0:\\n            self.countdown_start_time = current_time\\n        \\n        elapsed_time = int(current_time - self.countdown_start_time)\\n        \\n        if elapsed_time &gt;= interval_seconds:\\n            should_ring = True\\n            self.countdown_start_time = current_time\\n            status_message = \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\uff1a\\u65f6\\u95f4\\u5230\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n        else:\\n            status_message = \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\uff1a\\u7b49\\u5f85\\u4e2d...\\&quot;\\n            \\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        interval_seconds = int(float(self.app.minutes_var.get()) * 60)\\n        remaining_time = interval_seconds - int(time.time() - self.countdown_start_time)\\n        mins, secs = divmod(max(0, remaining_time), 60)\\n        return f\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a{mins:02d}:{secs:02d}\\&quot;\\n\\n# ----------------- MainApp -----------------\\nclass BellApp:\\n    def __init__(self, root):\\n        self.root = root\\n        self.root.title(\\&quot;\\u667a\\u80fd\\u54cd\\u94c3\\u5668\\&quot;)\\n        self.root.geometry(\\&quot;550x550\\&quot;)\\n        self.running = False\\n        self.reset_flag = False\\n        self.stop_flag = False\\n        self.volume_var = tk.IntVar(value=DEFAULT_VOLUME)\\n        self.waiting_for_user_after_bell = False\\n        self.reset_mode_var = tk.StringVar(value=DEFAULT_RESET_MODE)\\n        self.user_active_event = threading.Event()\\n        self.listener_mouse = None\\n        self.listener_keyboard = None\\n        self.window_focused = False\\n        self.is_mini_mode = tk.BooleanVar(value=False)\\n        self.config_manager = ConfigManager(self)\\n        self.region_detector = RegionColorDetector(self)\\n        self.network_detector = NetworkSpeedDetector(self)\\n        self.timer_detector = TimerDetector(self)\\n        self.active_detector = None\\n        self.start_cycle_time = 0\\n\\n        self.notebook = ttk.Notebook(root)\\n        self.tab_timer = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_timer, text=\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;)\\n        self.tab_region = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_region, text=\\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;)\\n        self.tab_network = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;)\\n\\n        self.bell_mode_frame = tk.LabelFrame(root, text=\\&quot;\\u54cd\\u94c3\\u6a21\\u5f0f\\&quot;, font=DEFAULT_FONT)\\n        self.mode_var = tk.StringVar(value=DEFAULT_BELL_MODE)\\n        tk.Radiobutton(self.bell_mode_frame, text=\\&quot;\\u54cd\\u4e00\\u4e0b\\&quot;, variable=self.mode_var, value=\\&quot;1\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(side=\\&quot;left\\&quot;, padx=5)\\n        tk.Radiobutton(self.bell_mode_frame, text=\\&quot;\\u6301\\u7eed\\u54cd\\u94c3\\&quot;, variable=self.mode_var, value=\\&quot;continuous\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(side=\\&quot;left\\&quot;, padx=5)\\n        tk.Label(self.bell_mode_frame, text=\\&quot;\\u6700\\u957f (\\u79d2)\\uff1a\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n        self.continuous_bell_duration_var = tk.StringVar(value=str(DEFAULT_CONTINUOUS_BELL_DURATION))\\n        tk.Entry(self.bell_mode_frame, textvariable=self.continuous_bell_duration_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n        self.continuous_bell_duration_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n\\n        time_frame = tk.Frame(self.tab_timer)\\n        time_frame.pack(pady=5)\\n        tk.Label(time_frame, text=\\&quot;\\u6bcf\\u9694\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0)\\n        self.minutes_var = tk.StringVar(value=str(DEFAULT_TIMER_MINUTES))\\n        tk.Entry(time_frame, textvariable=self.minutes_var, width=5, font=DEFAULT_FONT).grid(row=0, column=1)\\n        self.minutes_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(time_frame, text=\\&quot;\\u5206\\u949f    \\u5171\\u54cd\\u94c3\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2)\\n        self.times_var = tk.StringVar(value=str(DEFAULT_TIMER_TIMES))\\n        tk.Entry(time_frame, textvariable=self.times_var, width=5, font=DEFAULT_FONT).grid(row=0, column=3)\\n        self.times_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(time_frame, text=\\&quot;\\u6b21\\&quot;, font=DEFAULT_FONT).grid(row=0, column=4)\\n\\n        timer_reset_frame = tk.LabelFrame(self.tab_timer, text=\\&quot;\\u54cd\\u94c3\\u540e\\u91cd\\u7f6e\\u65b9\\u5f0f\\&quot;, font=DEFAULT_FONT)\\n        timer_reset_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n        tk.Radiobutton(timer_reset_frame, text=\\&quot;\\u9f20\\u6807\\u79fb\\u52a8\\u540e\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;mouse_move\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n        tk.Radiobutton(timer_reset_frame, text=\\&quot;\\u7a97\\u53e3\\u9009\\u4e2d\\u540e\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;window_focus\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n        tk.Radiobutton(timer_reset_frame, text=\\&quot;\\u4e0d\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;no_reset\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n\\n        region_frame = tk.LabelFrame(self.tab_region, text=\\&quot;\\u5c4f\\u5e55\\u533a\\u57df\\u5750\\u6807 (\\u50cf\\u7d20)\\&quot;, font=DEFAULT_FONT)\\n        region_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n        tk.Label(region_frame, text=\\&quot;\\u5de6\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0)\\n        self.left_var = tk.StringVar(value=str(DEFAULT_REGION_LEFT))\\n        tk.Entry(region_frame, textvariable=self.left_var, width=6, font=DEFAULT_FONT).grid(row=0, column=1)\\n        self.left_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(region_frame, text=\\&quot;\\u4e0a\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2)\\n        self.top_var = tk.StringVar(value=str(DEFAULT_REGION_TOP))\\n        tk.Entry(region_frame, textvariable=self.top_var, width=6, font=DEFAULT_FONT).grid(row=0, column=3)\\n        self.top_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(region_frame, text=\\&quot;\\u53f3\\&quot;, font=DEFAULT_FONT).grid(row=0, column=4)\\n        self.right_var = tk.StringVar(value=str(DEFAULT_REGION_RIGHT))\\n        tk.Entry(region_frame, textvariable=self.right_var, width=6, font=DEFAULT_FONT).grid(row=0, column=5)\\n        self.right_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(region_frame, text=\\&quot;\\u4e0b\\&quot;, font=DEFAULT_FONT).grid(row=0, column=6)\\n        self.bottom_var = tk.StringVar(value=str(DEFAULT_REGION_BOTTOM))\\n        tk.Entry(region_frame, textvariable=self.bottom_var, width=6, font=DEFAULT_FONT).grid(row=0, column=7)\\n        self.bottom_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        self.select_region_btn = tk.Button(region_frame, text=\\&quot;\\u6846\\u9009\\u533a\\u57df\\&quot;, font=DEFAULT_FONT, command=self.open_region_selector)\\n        self.select_region_btn.grid(row=1, column=0, columnspan=8, pady=5, sticky=\\&quot;we\\&quot;)\\n        \\n        dark_threshold_frame = tk.Frame(region_frame)\\n        dark_threshold_frame.grid(row=2, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(dark_threshold_frame, text=\\&quot;\\u9ed1\\u6697\\u9608\\u503c (0-255\\uff0c\\u503c\\u8d8a\\u5c0f\\u8d8a\\u9ed1)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_threshold_var = tk.StringVar(value=str(DEFAULT_DARK_THRESHOLD))\\n        tk.Entry(dark_threshold_frame, textvariable=self.dark_threshold_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_threshold_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        \\n        dark_duration_frame = tk.Frame(region_frame)\\n        dark_duration_frame.grid(row=3, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(dark_duration_frame, text=\\&quot;\\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f (\\u79d2\\uff0c\\u9ed8\\u8ba420)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_duration_sec_var = tk.StringVar(value=str(DEFAULT_DARK_DURATION_SEC))\\n        tk.Entry(dark_duration_frame, textvariable=self.dark_duration_sec_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_duration_sec_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n\\n        max_wait_time_frame = tk.Frame(region_frame)\\n        max_wait_time_frame.grid(row=4, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(max_wait_time_frame, text=\\&quot;\\u6700\\u5927\\u7b49\\u5f85\\u65f6\\u95f4 (\\u5206\\u949f\\uff0c\\u9ed8\\u8ba410)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.max_wait_minutes_var = tk.StringVar(value=str(DEFAULT_MAX_WAIT_MINUTES))\\n        tk.Entry(max_wait_time_frame, textvariable=self.max_wait_minutes_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.max_wait_minutes_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n\\n        self.region_status_label = tk.Label(self.tab_region, text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;, font=STATUS_FONT)\\n        self.region_status_label.pack(pady=2)\\n\\n        net_speed_frame = tk.LabelFrame(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u8bbe\\u7f6e\\&quot;, font=DEFAULT_FONT)\\n        net_speed_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n        tk.Label(net_speed_frame, text=\\&quot;\\u4e0b\\u8f7d\\u901f\\u5ea6\\u5c0f\\u4e8e\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0, pady=5)\\n        self.speed_threshold_kb_var = tk.StringVar(value=str(DEFAULT_SPEED_THRESHOLD_KB))\\n        tk.Entry(net_speed_frame, textvariable=self.speed_threshold_kb_var, width=8, font=DEFAULT_FONT).grid(row=0, column=1, pady=5)\\n        self.speed_threshold_kb_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(net_speed_frame, text=\\&quot;KB\\\/S\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2, pady=5)\\n        tk.Label(net_speed_frame, text=\\&quot;\\u5e76\\u6301\\u7eed\\&quot;, font=DEFAULT_FONT).grid(row=1, column=0, pady=5)\\n        self.low_speed_duration_sec_var = tk.StringVar(value=str(DEFAULT_LOW_SPEED_DURATION_SEC))\\n        tk.Entry(net_speed_frame, textvariable=self.low_speed_duration_sec_var, width=8, font=DEFAULT_FONT).grid(row=1, column=1, pady=5)\\n        self.low_speed_duration_sec_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(net_speed_frame, text=\\&quot;\\u79d2\\u65f6\\u54cd\\u94c3\\&quot;, font=DEFAULT_FONT).grid(row=1, column=2, pady=5)\\n        tk.Label(net_speed_frame, text=\\&quot;\\u6bcf\\u9694\\&quot;, font=DEFAULT_FONT).grid(row=2, column=0, pady=5)\\n        self.check_interval_sec_var = tk.StringVar(value=str(DEFAULT_CHECK_INTERVAL_SEC))\\n        tk.Entry(net_speed_frame, textvariable=self.check_interval_sec_var, width=8, font=DEFAULT_FONT).grid(row=2, column=1, pady=5)\\n        self.check_interval_sec_var.trace(\\&quot;w\\&quot;, lambda *args: self.save_config())\\n        tk.Label(net_speed_frame, text=\\&quot;\\u79d2\\u68c0\\u6d4b\\u4e00\\u6b21\\&quot;, font=DEFAULT_FONT).grid(row=2, column=2, pady=5)\\n\\n        network_reset_frame = tk.LabelFrame(self.tab_network, text=\\&quot;\\u54cd\\u94c3\\u540e\\u91cd\\u7f6e\\u65b9\\u5f0f\\&quot;, font=DEFAULT_FONT)\\n        network_reset_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n        tk.Radiobutton(network_reset_frame, text=\\&quot;\\u9f20\\u6807\\u79fb\\u52a8\\u540e\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;mouse_move\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n        tk.Radiobutton(network_reset_frame, text=\\&quot;\\u7a97\\u53e3\\u9009\\u4e2d\\u540e\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;window_focus\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n        tk.Radiobutton(network_reset_frame, text=\\&quot;\\u4e0d\\u91cd\\u65b0\\u68c0\\u6d4b\\&quot;, variable=self.reset_mode_var, value=\\&quot;no_reset\\&quot;, font=DEFAULT_FONT, command=self.save_config).pack(anchor=\\&quot;w\\&quot;, padx=5)\\n\\n        self.network_status_label = tk.Label(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;, font=STATUS_FONT)\\n        self.network_status_label.pack(pady=2)\\n        self.current_speed_label = tk.Label(self.tab_network, text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;, font=STATUS_FONT, fg=\\&quot;darkgreen\\&quot;)\\n        self.current_speed_label.pack(pady=2)\\n\\n        self.vol_frame = tk.Frame(root)\\n        tk.Label(self.vol_frame, text=\\&quot;\\u5168\\u5c40\\u97f3\\u91cf\\uff1a\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.volume_slider = tk.Scale(self.vol_frame, from_=0, to=100, orient=\\&quot;horizontal\\&quot;,\\n                                     variable=self.volume_var, length=200, command=lambda _: self.save_config())\\n        self.volume_slider.pack(side=\\&quot;left\\&quot;)\\n\\n        self.btn_frame = tk.Frame(root)\\n        self.start_stop_btn = tk.Button(self.btn_frame, text=\\&quot;\\u5f00\\u59cb\\&quot;, command=self.toggle_start_stop, font=DEFAULT_FONT, width=10)\\n        self.start_stop_btn.grid(row=0, column=0, padx=5)\\n        tk.Button(self.btn_frame, text=\\&quot;\\u91cd\\u65b0\\u5f00\\u59cb\\&quot;, command=self.reset, font=DEFAULT_FONT, width=10).grid(row=0, column=1, padx=5)\\n\\n        self.countdown_label = tk.Label(root, text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;, font=COUNTDOWN_FONT, fg=\\&quot;blue\\&quot;)\\n        self.status_label = tk.Label(root, text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;, font=STATUS_FONT)\\n\\n        self.mini_frame = tk.Frame(root)\\n        self.mini_countdown_label = tk.Label(self.mini_frame, text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;, font=COUNTDOWN_FONT, fg=\\&quot;blue\\&quot;)\\n        self.mini_countdown_label.pack(pady=2)\\n        self.mini_status_label = tk.Label(self.mini_frame, text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;, font=STATUS_FONT)\\n        self.mini_status_label.pack(pady=2)\\n        self.mini_speed_label = tk.Label(self.mini_frame, text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;, font=STATUS_FONT, fg=\\&quot;darkgreen\\&quot;)\\n        self.mini_speed_label.pack(pady=2)\\n        self.mini_btn_frame = tk.Frame(self.mini_frame)\\n        self.mini_btn_frame.pack(pady=5)\\n        self.mini_start_stop_btn = tk.Button(self.mini_btn_frame, text=\\&quot;\\u5f00\\u59cb\\&quot;, command=self.toggle_start_stop, font=DEFAULT_FONT, width=10)\\n        self.mini_start_stop_btn.grid(row=0, column=0, padx=5)\\n        tk.Button(self.mini_btn_frame, text=\\&quot;\\u91cd\\u65b0\\u5f00\\u59cb\\&quot;, command=self.reset, font=DEFAULT_FONT, width=10).grid(row=0, column=1, padx=5)\\n\\n        self.toggle_mode_btn = tk.Button(root, text=\\&quot;\\u5207\\u6362\\u5230\\u5c0f\\u7a97\\u53e3\\u6a21\\u5f0f\\&quot;, command=self.toggle_window_mode, font=DEFAULT_FONT)\\n        self.toggle_mode_btn.pack(pady=5)\\n\\n        self.notebook.pack(pady=5, expand=True, fill=\\&quot;both\\&quot;)\\n        self.bell_mode_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n        self.vol_frame.pack(pady=5)\\n        self.btn_frame.pack(pady=5)\\n        self.countdown_label.pack(pady=2)\\n        self.status_label.pack(pady=2)\\n\\n        self.root.bind(\\&quot;&lt;FocusIn&gt;\\&quot;, self.on_window_focus)\\n        self.root.bind(\\&quot;&lt;FocusOut&gt;\\&quot;, self.on_window_focus_out)\\n        self.notebook.bind(\\&quot;&lt;&lt;NotebookTabChanged&gt;&gt;\\&quot;, self.on_tab_changed)\\n        self.config_manager.load_config()\\n\\n    def save_config(self):\\n        self.config_manager.save_config()\\n\\n    def toggle_window_mode(self):\\n        self.is_mini_mode.set(not self.is_mini_mode.get())\\n        if self.is_mini_mode.get():\\n            self.notebook.pack_forget()\\n            self.bell_mode_frame.pack_forget()\\n            self.vol_frame.pack_forget()\\n            self.btn_frame.pack_forget()\\n            self.countdown_label.pack_forget()\\n            self.status_label.pack_forget()\\n            self.toggle_mode_btn.config(text=\\&quot;\\u5207\\u6362\\u5230\\u6b63\\u5e38\\u6a21\\u5f0f\\&quot;)\\n            self.mini_frame.pack(pady=5, fill=\\&quot;both\\&quot;, expand=True)\\n            self.root.geometry(\\&quot;300x180\\&quot;)\\n        else:\\n            self.mini_frame.pack_forget()\\n            self.notebook.pack(pady=5, expand=True, fill=\\&quot;both\\&quot;)\\n            self.bell_mode_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n            self.vol_frame.pack(pady=5)\\n            self.btn_frame.pack(pady=5)\\n            self.countdown_label.pack(pady=2)\\n            self.status_label.pack(pady=2)\\n            self.toggle_mode_btn.config(text=\\&quot;\\u5207\\u6362\\u5230\\u5c0f\\u7a97\\u53e3\\u6a21\\u5f0f\\&quot;)\\n            self.root.geometry(\\&quot;550x550\\&quot;)\\n        self.save_config()\\n\\n    def on_window_focus(self, event):\\n        self.window_focused = True\\n        if self.running and self.reset_mode_var.get() == \\&quot;window_focus\\&quot;:\\n            self.user_active_event.set()\\n\\n    def on_window_focus_out(self, event):\\n        self.window_focused = False\\n\\n    def on_tab_changed(self, event):\\n        if self.running:\\n            self.stop()\\n        self.countdown_label.config(text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;)\\n        self.mini_countdown_label.config(text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;)\\n        self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;)\\n        self.mini_status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;)\\n        self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;)\\n        self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;)\\n        self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;)\\n        self.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;)\\n        self.waiting_for_user_after_bell = False\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n        self.save_config()\\n\\n    def open_region_selector(self):\\n        def callback(l, t, r, b):\\n            self.left_var.set(str(l))\\n            self.top_var.set(str(t))\\n            self.right_var.set(str(r))\\n            self.bottom_var.set(str(b))\\n            self.region_status_label.config(text=f\\&quot;\\u533a\\u57df\\u5750\\u6807\\u8bbe\\u7f6e\\u4e3a\\uff1a({l},{t},{r},{b})\\&quot;)\\n            self.save_config()\\n        RegionSelector(self.root, callback)\\n\\n    def on_user_active(self, *args):\\n        if self.reset_mode_var.get() == \\&quot;mouse_move\\&quot;:\\n            self.user_active_event.set()\\n\\n    def toggle_start_stop(self):\\n        if self.running:\\n            self.stop()\\n        else:\\n            self.start()\\n\\n    def start(self):\\n        if self.running:\\n            return\\n        current_tab_name = self.notebook.tab(self.notebook.select(), \\&quot;text\\&quot;) if not self.is_mini_mode.get() else self.config_manager.load_config()[&#039;tab_selected&#039;]\\n        \\n        try:\\n            self.total_times = int(self.times_var.get())\\n            if self.total_times &lt;= 0:\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u603b\\u54cd\\u94c3\\u6b21\\u6570\\u5fc5\\u987b\\u5927\\u4e8e0\\u3002\\&quot;)\\n                return\\n            volume_val = self.volume_var.get()\\n            if not (0 &lt;= volume_val &lt;= 100):\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u97f3\\u91cf\\u5fc5\\u987b\\u57280\\u5230100\\u4e4b\\u95f4\\u3002\\&quot;)\\n                return\\n            continuous_bell_duration = int(self.continuous_bell_duration_var.get())\\n            if continuous_bell_duration &lt;= 0:\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u957f\\u5fc5\\u987b\\u5927\\u4e8e0\\u79d2\\u3002\\&quot;)\\n                return\\n            if current_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                self.active_detector = self.region_detector\\n                _l, _t, _r, _b = int(self.left_var.get()), int(self.top_var.get()), \\\\\\n                                 int(self.right_var.get()), int(self.bottom_var.get())\\n                if _l &gt;= _r or _t &gt;= _b:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u533a\\u57df\\u5750\\u6807\\u8bbe\\u7f6e\\u6709\\u8bef\\uff0c\\u53f3\\u5750\\u6807\\u5fc5\\u987b\\u5927\\u4e8e\\u5de6\\u5750\\u6807\\uff0c\\u4e0b\\u5750\\u6807\\u5fc5\\u987b\\u5927\\u4e8e\\u4e0a\\u5750\\u6807\\u3002\\&quot;)\\n                    return\\n                dark_threshold = int(self.dark_threshold_var.get())\\n                if not (0 &lt;= dark_threshold &lt;= 255):\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u9ed1\\u6697\\u9608\\u503c\\u5fc5\\u987b\\u57280\\u5230255\\u4e4b\\u95f4\\u3002\\&quot;)\\n                    return\\n                dark_duration_sec = int(self.dark_duration_sec_var.get())\\n                if dark_duration_sec &lt; 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f\\u4e0d\\u80fd\\u4e3a\\u8d1f\\u6570\\u3002\\&quot;)\\n                    return\\n                max_wait_minutes = float(self.max_wait_minutes_var.get())\\n                if max_wait_minutes &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u533a\\u57df\\u68c0\\u6d4b\\u6a21\\u5f0f\\u4e0b\\u7684\\u6700\\u5927\\u7b49\\u5f85\\u65f6\\u95f4\\u5fc5\\u987b\\u5927\\u4e8e0\\u5206\\u949f\\u3002\\&quot;)\\n                    return\\n                self.region_detector.reset_state()\\n                self.waiting_for_user_after_bell = False\\n            elif current_tab_name == \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;:\\n                self.active_detector = self.timer_detector\\n                interval_minutes = float(self.minutes_var.get())\\n                if interval_minutes &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\u6a21\\u5f0f\\u4e0b\\u7684\\u95f4\\u9694\\u65f6\\u95f4\\u5fc5\\u987b\\u5927\\u4e8e0\\u5206\\u949f\\u3002\\&quot;)\\n                    return\\n                self.waiting_for_user_after_bell = False\\n            elif current_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                self.active_detector = self.network_detector\\n                speed_threshold_kb = float(self.speed_threshold_kb_var.get())\\n                low_speed_duration_sec = int(self.low_speed_duration_sec_var.get())\\n                check_interval_sec = int(self.check_interval_sec_var.get())\\n                if speed_threshold_kb &lt;= 0 or low_speed_duration_sec &lt;= 0 or check_interval_sec &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u7684\\u6240\\u6709\\u8bbe\\u7f6e\\u503c\\u90fd\\u5fc5\\u987b\\u5927\\u4e8e0\\u3002\\&quot;)\\n                    return\\n                if check_interval_sec &gt; low_speed_duration_sec:\\n                    messagebox.showwarning(\\&quot;\\u8bbe\\u7f6e\\u5efa\\u8bae\\&quot;, \\&quot;\\u68c0\\u6d4b\\u95f4\\u9694\\u65f6\\u95f4\\u901a\\u5e38\\u5e94\\u5c0f\\u4e8e\\u4f4e\\u901f\\u6301\\u7eed\\u65f6\\u95f4\\uff0c\\u5426\\u5219\\u53ef\\u80fd\\u65e0\\u6cd5\\u51c6\\u786e\\u68c0\\u6d4b\\u6301\\u7eed\\u4f4e\\u901f\\u3002\\&quot;)\\n                self.network_detector.reset_state()\\n                self.network_detector.awaiting_significant_traffic = True\\n                self.waiting_for_user_after_bell = False\\n        except ValueError as e:\\n            messagebox.showerror(\\&quot;\\u683c\\u5f0f\\u9519\\u8bef\\&quot;, f\\&quot;\\u8bf7\\u8f93\\u5165\\u6709\\u6548\\u7684\\u6570\\u5b57\\uff0c\\u6216\\u68c0\\u67e5\\u8f93\\u5165\\u8303\\u56f4\\u3002\\\\n\\u9519\\u8bef\\uff1a{e}\\&quot;)\\n            return\\n        \\n        if self.active_detector is None:\\n            messagebox.showerror(\\&quot;\\u6a21\\u5f0f\\u9009\\u62e9\\&quot;, \\&quot;\\u8bf7\\u9009\\u62e9\\u4e00\\u4e2a\\u8fd0\\u884c\\u6a21\\u5f0f\\u3002\\&quot;)\\n            return\\n\\n        self.current_count = 1\\n        self.running = True\\n        self.stop_flag = False\\n        self.reset_flag = False\\n        self.user_active_event.clear()\\n        self.stop_listeners()\\n        self.listener_mouse = mouse.Listener(on_move=self.on_user_active,\\n                                            on_click=self.on_user_active,\\n                                            on_scroll=self.on_user_active)\\n        self.listener_keyboard = keyboard.Listener(on_press=self.on_user_active)\\n        self.listener_mouse.daemon = True\\n        self.listener_keyboard.daemon = True\\n        self.listener_mouse.start()\\n        self.listener_keyboard.start()\\n        self.start_stop_btn.config(text=\\&quot;\\u505c\\u6b62\\&quot;)\\n        self.mini_start_stop_btn.config(text=\\&quot;\\u505c\\u6b62\\&quot;)\\n        threading.Thread(target=self.run_timer, args=(current_tab_name,), daemon=True).start()\\n        self.save_config()\\n\\n    def stop_listeners(self):\\n        if self.listener_mouse is not None and self.listener_mouse.is_alive():\\n            try:\\n                self.listener_mouse.stop()\\n                self.listener_mouse.join(timeout=1.0)\\n            except RuntimeError:\\n                pass\\n            finally:\\n                self.listener_mouse = None\\n        if self.listener_keyboard is not None and self.listener_keyboard.is_alive():\\n            try:\\n                self.listener_keyboard.stop()\\n                self.listener_keyboard.join(timeout=1.0)\\n            except RuntimeError:\\n                pass\\n            finally:\\n                self.listener_keyboard = None\\n\\n    def reset(self):\\n        if not self.running:\\n            self.start()\\n            return\\n        self.reset_flag = True\\n        self.user_active_event.set()\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n        self.waiting_for_user_after_bell = False\\n\\n    def stop(self):\\n        if not self.running:\\n            return\\n        self.running = False\\n        self.stop_flag = True\\n        self.user_active_event.set()\\n        self.stop_listeners()\\n        self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u5df2\\u505c\\u6b62\\&quot;))\\n        self.root.after(0, lambda: self.mini_countdown_label.config(text=\\&quot;\\u5df2\\u505c\\u6b62\\&quot;))\\n        self.root.after(0, lambda: self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n        self.root.after(0, lambda: self.mini_status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n        self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u542f\\u7528\\&quot;))\\n        self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u542f\\u7528\\&quot;))\\n        self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n        self.root.after(0, lambda: self.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n        self.root.after(0, lambda: self.start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n        self.root.after(0, lambda: self.mini_start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n        self.waiting_for_user_after_bell = False\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n\\n    def run_timer(self, active_tab_name):\\n        print(f\\&quot;[{time.time():.2f}] run_timer \\u7ebf\\u7a0b\\u542f\\u52a8. \\u5f53\\u524d\\u54cd\\u94c3\\u6b21\\u6570: {self.current_count}\\\/{self.total_times}\\&quot;)\\n        update_interval = 5  # \\u6bcf 5 \\u6b21\\u5faa\\u73af\\u66f4\\u65b0\\u4e00\\u6b21 UI\\n        loop_count = 0\\n        while self.current_count &lt;= self.total_times and not self.stop_flag:\\n            self.root.after(0, lambda: self.status_label.config(text=f\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a{self.current_count} \\\/ {self.total_times}\\&quot;))\\n            self.root.after(0, lambda: self.mini_status_label.config(text=f\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a{self.current_count} \\\/ {self.total_times}\\&quot;))\\n            should_ring_this_cycle = False\\n\\n            if self.waiting_for_user_after_bell:\\n                self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                self.root.after(0, lambda: self.mini_countdown_label.config(text=\\&quot;\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                print(f\\&quot;[{time.time():.2f}] \\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001.\\&quot;)\\n                if active_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                    self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u54cd\\u94c3\\u540e\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\&quot;, fg=\\&quot;orange\\&quot;))\\n                elif active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                    self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u54cd\\u94c3\\u540e\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\&quot;, fg=\\&quot;orange\\&quot;))\\n                    self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n                    self.root.after(0, lambda: self.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n                self.user_active_event.clear()\\n                while not self.stop_flag and not self.reset_flag and not self.user_active_event.is_set():\\n                    time.sleep(0.1)\\n                if self.user_active_event.is_set():\\n                    print(f\\&quot;[{time.time():.2f}] \\u7528\\u6237\\u64cd\\u4f5c\\u89e3\\u9664\\u7b49\\u5f85\\u72b6\\u6001.\\&quot;)\\n                    self.user_active_event.clear()\\n                    self.waiting_for_user_after_bell = False\\n                    if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                        self.network_detector.awaiting_significant_traffic = True\\n                    continue\\n                if self.reset_flag:\\n                    print(f\\&quot;[{time.time():.2f}] Reset \\u6309\\u94ae\\u88ab\\u70b9\\u51fb\\uff0c\\u91cd\\u7f6e\\u4efb\\u52a1.\\&quot;)\\n                    self.current_count = 1\\n                    self.reset_flag = False\\n                    self.region_detector.reset_state()\\n                    self.network_detector.reset_state()\\n                    self.timer_detector.reset_state()\\n                    self.waiting_for_user_after_bell = False\\n                    continue\\n                if self.stop_flag:\\n                    print(f\\&quot;[{time.time():.2f}] Stop \\u6309\\u94ae\\u88ab\\u70b9\\u51fb\\uff0c\\u505c\\u6b62\\u4efb\\u52a1.\\&quot;)\\n                    break\\n\\n            self.start_cycle_time = time.time()\\n            print(f\\&quot;[{time.time():.2f}] \\u8fdb\\u5165\\u5e38\\u89c4\\u68c0\\u6d4b\\u5468\\u671f. \\u5468\\u671f\\u5f00\\u59cb\\u65f6\\u95f4: {self.start_cycle_time:.2f}\\&quot;)\\n            \\n            while True:\\n                if self.stop_flag or self.reset_flag:\\n                    print(f\\&quot;[{time.time():.2f}] \\u68c0\\u6d4b\\u5468\\u671f\\u88ab\\u505c\\u6b62\\u6216\\u91cd\\u7f6e\\u6807\\u5fd7\\u6253\\u65ad.\\&quot;)\\n                    break\\n                if self.active_detector:\\n                    should_ring_this_cycle, status_message = self.active_detector.check_condition()\\n                    loop_count += 1\\n                    if loop_count % update_interval == 0:\\n                        self.root.after(0, lambda: self.countdown_label.config(text=self.active_detector.get_display_info()))\\n                        self.root.after(0, lambda: self.mini_countdown_label.config(text=self.active_detector.get_display_info()))\\n                        loop_count = 0\\n                    if should_ring_this_cycle:\\n                        print(f\\&quot;[{time.time():.2f}] \\u68c0\\u6d4b\\u6761\\u4ef6\\u6ee1\\u8db3\\uff0c\\u51c6\\u5907\\u54cd\\u94c3.\\&quot;)\\n                        break\\n                    if active_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                        time.sleep(2)  # \\u589e\\u52a0\\u68c0\\u6d4b\\u95f4\\u9694\\u5230 2 \\u79d2\\n                    elif active_tab_name == \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;:\\n                        time.sleep(1)\\n                    elif active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                        sleep_interval = int(self.check_interval_sec_var.get())\\n                        time.sleep(sleep_interval)\\n                        print(f\\&quot;[{time.time():.2f}] \\u7f51\\u901f\\u68c0\\u6d4b\\uff0c\\u4f11\\u7720 {sleep_interval} \\u79d2.\\&quot;)\\n\\n            if self.stop_flag:\\n                print(f\\&quot;[{time.time():.2f}] \\u5185\\u90e8\\u5faa\\u73af\\u56e0 Stop \\u6807\\u5fd7\\u9000\\u51fa.\\&quot;)\\n                break\\n            if self.reset_flag:\\n                print(f\\&quot;[{time.time():.2f}] \\u5185\\u90e8\\u5faa\\u73af\\u56e0 Reset \\u6807\\u5fd7\\u9000\\u51fa\\uff0c\\u6267\\u884c\\u5b8c\\u5168\\u91cd\\u7f6e.\\&quot;)\\n                self.current_count = 1\\n                self.reset_flag = False\\n                self.user_active_event.clear()\\n                self.region_detector.reset_state()\\n                self.network_detector.reset_state()\\n                self.timer_detector.reset_state()\\n                self.waiting_for_user_after_bell = False\\n                continue\\n            \\n            if should_ring_this_cycle:\\n                print(f\\&quot;[{time.time():.2f}] \\u5f00\\u59cb\\u54cd\\u94c3\\u903b\\u8f91. \\u6a21\\u5f0f: {self.mode_var.get()}\\&quot;)\\n                set_system_volume(self.volume_var.get())\\n                bell_mode_val = self.mode_var.get()\\n                \\n                if bell_mode_val == \\&quot;continuous\\&quot;:\\n                    self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\\\U0001F514 \\u6301\\u7eed\\u54cd\\u94c3\\u4e2d\\uff08\\u8bf7\\u64cd\\u4f5c\\u9f20\\u6807\\u952e\\u76d8\\u7ec8\\u6b62\\uff09\\&quot;))\\n                    self.root.after(0, lambda: self.mini_countdown_label.config(text=\\&quot;\\\\U0001F514 \\u6301\\u7eed\\u54cd\\u94c3\\u4e2d\\uff08\\u8bf7\\u64cd\\u4f5c\\u9f20\\u6807\\u952e\\u76d8\\u7ec8\\u6b62\\uff09\\&quot;))\\n                    self.user_active_event.clear()\\n                    continuous_bell_start_time = time.time()\\n                    continuous_bell_duration = int(self.continuous_bell_duration_var.get())\\n                    while not self.user_active_event.is_set() and not self.stop_flag and not self.reset_flag:\\n                        play_bell_sound()\\n                        if time.time() - continuous_bell_start_time &gt;= continuous_bell_duration:\\n                            self.root.after(0, lambda dur=continuous_bell_duration: self.countdown_label.config(text=f\\&quot;\\ud83d\\udd14 \\u54cd\\u94c3{dur}\\u79d2\\uff0c\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                            self.root.after(0, lambda dur=continuous_bell_duration: self.mini_countdown_label.config(text=f\\&quot;\\ud83d\\udd14 \\u54cd\\u94c3{dur}\\u79d2\\uff0c\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                            if active_tab_name in [\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;]:\\n                                self.waiting_for_user_after_bell = (self.reset_mode_var.get() != \\&quot;no_reset\\&quot;)\\n                            else:\\n                                self.waiting_for_user_after_bell = True\\n                            print(f\\&quot;[{time.time():.2f}] \\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u95f4\\u5230\\uff0c\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c.\\&quot;)\\n                            break\\n                        if self.reset_mode_var.get() == \\&quot;window_focus\\&quot; and self.window_focused:\\n                            self.user_active_event.set()\\n                        if self.user_active_event.wait(timeout=1):\\n                            print(f\\&quot;[{time.time():.2f}] \\u7528\\u6237\\u64cd\\u4f5c\\u4e2d\\u65ad\\u6301\\u7eed\\u54cd\\u94c3.\\&quot;)\\n                            break\\n                    if self.user_active_event.is_set():\\n                        self.user_active_event.clear()\\n                        if active_tab_name in [\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;]:\\n                            self.waiting_for_user_after_bell = (self.reset_mode_var.get() != \\&quot;no_reset\\&quot;)\\n                        else:\\n                            self.waiting_for_user_after_bell = True\\n                        if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                            self.network_detector.awaiting_significant_traffic = True\\n                        continue\\n                    elif self.reset_flag:\\n                        continue\\n                    elif self.stop_flag:\\n                        break\\n                    if self.waiting_for_user_after_bell:\\n                        if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                            self.network_detector.awaiting_significant_traffic = True\\n                        continue\\n                else:\\n                    self.root.after(0, lambda: self.countdown_label.config(text=f\\&quot;\\\\U0001F514 \\u54cd\\u94c3 1 \\u6b21\\&quot;))\\n                    self.root.after(0, lambda: self.mini_countdown_label.config(text=f\\&quot;\\\\U0001F514 \\u54cd\\u94c3 1 \\u6b21\\&quot;))\\n                    print(f\\&quot;[{time.time():.2f}] \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\uff0c\\u64ad\\u653e\\u54cd\\u94c3.\\&quot;)\\n                    play_bell_sound()\\n                    self.user_active_event.clear()\\n                    if self.reset_mode_var.get() == \\&quot;window_focus\\&quot; and self.window_focused:\\n                        self.user_active_event.set()\\n                    if self.user_active_event.wait(timeout=0.5):\\n                        print(f\\&quot;[{time.time():.2f}] \\u7528\\u6237\\u64cd\\u4f5c\\u5728\\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u54cd\\u94c3\\u671f\\u95f4\\u53d1\\u751f.\\&quot;)\\n                        self.user_active_event.clear()\\n                        if active_tab_name in [\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;]:\\n                            self.waiting_for_user_after_bell = (self.reset_mode_var.get() != \\&quot;no_reset\\&quot;)\\n                        else:\\n                            self.waiting_for_user_after_bell = True\\n                        if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                            self.network_detector.awaiting_significant_traffic = True\\n                        continue\\n                    if active_tab_name in [\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;]:\\n                        self.waiting_for_user_after_bell = (self.reset_mode_var.get() != \\&quot;no_reset\\&quot;)\\n                    else:\\n                        self.waiting_for_user_after_bell = True\\n                    print(f\\&quot;[{time.time():.2f}] \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u54cd\\u94c3\\u5b8c\\u6210.\\&quot;)\\n\\n                if not self.waiting_for_user_after_bell:\\n                    self.current_count += 1\\n                    print(f\\&quot;[{time.time():.2f}] \\u54cd\\u94c3\\u6b21\\u6570\\u589e\\u52a0\\u5230 {self.current_count}.\\&quot;)\\n                self.user_active_event.clear()\\n\\n        self.running = False\\n        self.stop_listeners()\\n        print(f\\&quot;[{time.time():.2f}] run_timer \\u7ebf\\u7a0b\\u7ed3\\u675f.\\&quot;)\\n        if not self.stop_flag:\\n            self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u2705 \\u5b8c\\u6210\\&quot;))\\n            self.root.after(0, lambda: self.mini_countdown_label.config(text=\\&quot;\\u2705 \\u5b8c\\u6210\\&quot;))\\n            self.root.after(0, lambda: self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n            self.root.after(0, lambda: self.mini_status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n            self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7ed3\\u675f\\&quot;))\\n            self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7ed3\\u675f\\&quot;))\\n            self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n            self.root.after(0, lambda: self.mini_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n        self.waiting_for_user_after_bell = False\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n        self.root.after(0, lambda: self.start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n        self.root.after(0, lambda: self.mini_start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n\\nif __name__ == \\&quot;__main__\\&quot;:\\n    if platform.system() == \\&quot;Windows\\&quot;:\\n        try:\\n            is_admin = (ctypes.windll.shell32.IsUserAnAdmin() != 0)\\n        except Exception:\\n            is_admin = False\\n        if not is_admin:\\n            try:\\n                script = os.path.abspath(sys.argv[0])\\n                python_exe = sys.executable\\n                command = python_exe\\n                ctypes.windll.shell32.ShellExecuteW(None, \\&quot;runas\\&quot;, command, script, None, 1)\\n                sys.exit(0)\\n            except Exception as e:\\n                print(f\\&quot;[\\u65e0\\u6cd5\\u4ee5\\u7ba1\\u7406\\u5458\\u6743\\u9650\\u91cd\\u65b0\\u542f\\u52a8] {e}\\&quot;)\\n                pass\\n    root = tk.Tk()\\n    try:\\n        app = BellApp(root)\\n        root.mainloop()\\n    except Exception as e:\\n        error_message = f\\&quot;\\u7a0b\\u5e8f\\u53d1\\u751f\\u610f\\u5916\\u9519\\u8bef\\uff1a\\\\n{e}\\\\n\\\\n\\u8be6\\u7ec6\\u4fe1\\u606f\\u8bf7\\u67e5\\u770b\\u63a7\\u5236\\u53f0\\u3002\\&quot;\\n        print(\\&quot;\\\\n\\&quot; + \\&quot;=\\&quot;*50)\\n        print(\\&quot;\\u7a0b\\u5e8f\\u53d1\\u751f\\u672a\\u6355\\u83b7\\u7684\\u9519\\u8bef\\uff01\\&quot;)\\n        traceback.print_exc()\\n        print(\\&quot;=\\&quot;*50 + \\&quot;\\\\n\\&quot;)\\n        messagebox.showerror(\\&quot;\\u7a0b\\u5e8f\\u9519\\u8bef\\&quot;, error_message)\\n        sys.exit(1)&quot;,&quot;codeTypo&quot;:{&quot;desktop&quot;:9,&quot;tablet&quot;:15,&quot;mobile&quot;:14},&quot;height&quot;:{&quot;desktop&quot;:&quot;500px&quot;,&quot;tablet&quot;:&quot;0px&quot;,&quot;mobile&quot;:&quot;0px&quot;},&quot;align&quot;:&quot;&quot;,&quot;lineNumbers&quot;:true,&quot;theme&quot;:&quot;default&quot;,&quot;clipBoard&quot;:true,&quot;wordWrap&quot;:true,&quot;width&quot;:{&quot;desktop&quot;:&quot;100%&quot;,&quot;tablet&quot;:&quot;100%&quot;,&quot;mobile&quot;:&quot;100%&quot;},&quot;padding&quot;:{&quot;top&quot;:&quot;0px&quot;,&quot;right&quot;:&quot;0px&quot;,&quot;bottom&quot;:&quot;0px&quot;,&quot;left&quot;:&quot;0px&quot;},&quot;background&quot;:{&quot;color&quot;:&quot;#d3cfcf42&quot;},&quot;layout&quot;:{&quot;align&quot;:&quot;left&quot;},&quot;border&quot;:{&quot;color&quot;:&quot;#000&quot;,&quot;style&quot;:&quot;solid&quot;,&quot;width&quot;:&quot;0px&quot;},&quot;shadow&quot;:[],&quot;alignment&quot;:&quot;center&quot;,&quot;clipBoardColors&quot;:{&quot;color&quot;:&quot;#fff&quot;,&quot;bg&quot;:&quot;#00000024&quot;}}'><\/div>\r\n\r\n\t\t\n\n\n<h1 class=\"wp-block-heading has-text-align-center\">V7.3<\/h1>\n\n\n\n<h1 class=\"wp-block-heading\">\u622a\u56fe<\/h1>\n\n\n\n<div class=\"wp-block-cover\"><img loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"533\" class=\"wp-block-cover__image-background wp-image-3623\" alt=\"\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-25.png\" data-object-fit=\"cover\"\/><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow\">\n<p class=\"has-text-align-center has-large-font-size\">\u7f51\u901f\u53d8\u5316\u68c0\u6d4b\u54cd\u94c3<\/p>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-cover\"><img loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"533\" class=\"wp-block-cover__image-background wp-image-3624\" alt=\"\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-26.png\" data-object-fit=\"cover\"\/><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow\">\n<p class=\"has-text-align-center has-large-font-size\">\u533a\u57df\u989c\u8272\u53d8\u5316\u68c0\u6d4b\u54cd\u94c3<\/p>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-cover\"><img loading=\"lazy\" decoding=\"async\" width=\"552\" height=\"533\" class=\"wp-block-cover__image-background wp-image-3625\" alt=\"\" src=\"https:\/\/blog.kangyue.pro\/wp-content\/uploads\/2025\/07\/image-27.png\" data-object-fit=\"cover\"\/><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-flow wp-block-cover-is-layout-flow\">\n<p class=\"has-text-align-center has-large-font-size\">\u56fa\u5b9a\u65f6\u95f4\u54cd\u94c3<\/p>\n<\/div><\/div>\n\n\n\n<h1 class=\"wp-block-heading\">\u4ee3\u7801<\/h1>\n\n\n\n<p>V7.3<\/p>\n\n\n\t\t<div class='wp-block-bch-code-highlight  align' id='bhcCodeHighlight-984b21fe-9' data-attributes='{&quot;cId&quot;:&quot;984b21fe-9&quot;,&quot;language&quot;:&quot;python&quot;,&quot;code&quot;:&quot;# -*- coding: utf-8 -*-\\nimport sys\\nimport os\\nimport platform\\nimport ctypes\\nimport traceback # \\u5bfc\\u5165 traceback \\u6a21\\u5757\\u7528\\u4e8e\\u83b7\\u53d6\\u8be6\\u7ec6\\u9519\\u8bef\\u4fe1\\u606f\\n\\n# ----------------- \\u8bf7\\u6c42\\u7ba1\\u7406\\u5458\\u6743\\u9650 (\\u4ec5\\u9650Windows) -----------------\\n# \\u5fc5\\u987b\\u653e\\u5728\\u6240\\u6709 import \\u8bed\\u53e5\\u4e4b\\u524d\\uff0c\\u786e\\u4fdd\\u5728\\u4efb\\u4f55\\u4ee3\\u7801\\u6267\\u884c\\u524d\\u5c31\\u68c0\\u67e5\\u6743\\u9650\\n\\nif platform.system() == \\&quot;Windows\\&quot;:\\n    try:\\n        # \\u68c0\\u67e5\\u5f53\\u524d\\u662f\\u5426\\u5df2\\u7ecf\\u662f\\u7ba1\\u7406\\u5458\\u6743\\u9650\\n        is_admin = (os.getuid() == 0) # os.getuid() \\u5728Windows\\u4e0a\\u4e0d\\u53ef\\u7528\\n    except AttributeError:\\n        # \\u5bf9\\u4e8eWindows\\uff0c\\u901a\\u8fc7 ctypes \\u68c0\\u67e5\\n        try:\\n            is_admin = (ctypes.windll.shell32.IsUserAnAdmin() != 0)\\n        except Exception:\\n            is_admin = False # \\u65e0\\u6cd5\\u786e\\u5b9a\\uff0c\\u5047\\u8bbe\\u4e0d\\u662f\\u7ba1\\u7406\\u5458\\n\\n    if not is_admin:\\n        # \\u5982\\u679c\\u4e0d\\u662f\\u7ba1\\u7406\\u5458\\uff0c\\u5c1d\\u8bd5\\u4ee5\\u7ba1\\u7406\\u5458\\u6743\\u9650\\u91cd\\u65b0\\u542f\\u52a8\\u811a\\u672c\\n        try:\\n            # sys.argv[0] \\u662f\\u5f53\\u524d\\u811a\\u672c\\u7684\\u8def\\u5f84\\n            script = os.path.abspath(sys.argv[0])\\n            # \\u83b7\\u53d6\\u5f53\\u524dPython\\u89e3\\u91ca\\u5668\\u7684\\u8def\\u5f84\\n            python_exe = sys.executable\\n\\n            # \\u6784\\u9020\\u547d\\u4ee4\\u884c\\u53c2\\u6570\\n            # \\u4f7f\\u7528 pythonw.exe \\u8fd0\\u884c .pyw \\u6587\\u4ef6\\u53ef\\u4ee5\\u907f\\u514d\\u63a7\\u5236\\u53f0\\u7a97\\u53e3\\n            # \\u5bf9\\u4e8e .py \\u6587\\u4ef6\\uff0c\\u901a\\u5e38\\u4f7f\\u7528 python.exe\\n            if script.endswith(\\&quot;.pyw\\&quot;):\\n                command = python_exe # \\u76f4\\u63a5\\u8fd0\\u884cpythonw.exe\\n            else:\\n                command = python_exe # \\u8fd0\\u884cpython.exe\\n\\n            # \\u4f7f\\u7528 ShellExecuteW \\u4ee5 \\&quot;runas\\&quot; \\u52a8\\u8bcd\\u542f\\u52a8\\u8fdb\\u7a0b\\n            # \\u53c2\\u6570: \\u7236\\u7a97\\u53e3\\u53e5\\u67c4(0), \\u64cd\\u4f5c(\\&quot;runas\\&quot;), \\u6587\\u4ef6(\\u89e3\\u91ca\\u5668\\u8def\\u5f84), \\u53c2\\u6570(\\u811a\\u672c\\u8def\\u5f84), \\u76ee\\u5f55, \\u663e\\u793a\\u65b9\\u5f0f\\n            ctypes.windll.shell32.ShellExecuteW(\\n                None,  # Parent window handle\\n                \\&quot;runas\\&quot;, # Verb to run as administrator\\n                command, # Path to the interpreter (e.g., pythonw.exe)\\n                script,  # Arguments to the interpreter (e.g., your_script.pyw)\\n                None,    # Current directory (None means current working directory)\\n                1        # SW_SHOWNORMAL (show normally)\\n            )\\n            sys.exit(0) # \\u9000\\u51fa\\u5f53\\u524d\\uff08\\u975e\\u7ba1\\u7406\\u5458\\uff09\\u8fdb\\u7a0b\\n        except Exception as e:\\n            # \\u5982\\u679c\\u91cd\\u65b0\\u542f\\u52a8\\u5931\\u8d25\\uff0c\\u4f8b\\u5982\\u7528\\u6237\\u53d6\\u6d88UAC\\n            print(f\\&quot;\\u65e0\\u6cd5\\u4ee5\\u7ba1\\u7406\\u5458\\u6743\\u9650\\u91cd\\u65b0\\u542f\\u52a8: {e}\\&quot;)\\n            # \\u53ef\\u4ee5\\u9009\\u62e9\\u5728\\u8fd9\\u91cc\\u7ed9\\u7528\\u6237\\u4e00\\u4e2a\\u63d0\\u793a\\uff0c\\u6216\\u8005\\u7ee7\\u7eed\\u4ee5\\u975e\\u7ba1\\u7406\\u5458\\u6743\\u9650\\u8fd0\\u884c\\n            # \\u4f8b\\u5982\\uff1amessagebox.showerror(\\&quot;\\u6743\\u9650\\u4e0d\\u8db3\\&quot;, \\&quot;\\u65e0\\u6cd5\\u83b7\\u53d6\\u7ba1\\u7406\\u5458\\u6743\\u9650\\uff0c\\u90e8\\u5206\\u529f\\u80fd\\u53ef\\u80fd\\u53d7\\u9650\\u3002\\&quot;)\\n            pass # \\u7ee7\\u7eed\\u8fd0\\u884c\\uff0c\\u4f46\\u53ef\\u80fd\\u65e0\\u6cd5\\u5168\\u5c40\\u76d1\\u542c\\n\\n# ----------------- \\u8bf7\\u6c42\\u7ba1\\u7406\\u5458\\u6743\\u9650\\u7ed3\\u675f -----------------\\n\\n# \\u4ee5\\u4e0b\\u662f\\u60a8\\u73b0\\u6709\\u7684\\u6240\\u6709 import \\u8bed\\u53e5\\nimport time\\nimport platform\\nimport os\\nimport threading\\nimport tkinter as tk\\nfrom tkinter import messagebox, ttk\\nfrom PIL import ImageGrab, ImageStat\\nimport json\\n\\nfrom pynput import mouse, keyboard\\n\\ntry:\\n    import psutil # \\u5bfc\\u5165 psutil \\u5e93\\u7528\\u4e8e\\u672c\\u5730\\u7f51\\u5361\\u76d1\\u6d4b\\nexcept ImportError:\\n    messagebox.showerror(\\&quot;\\u7f3a\\u5c11\\u4f9d\\u8d56\\&quot;, \\&quot;\\u8bf7\\u5148\\u5b89\\u88c5 &#039;psutil&#039; \\u5e93\\uff1a\\\\npip install psutil\\&quot;)\\n    sys.exit() # \\u4f7f\\u7528 sys.exit() \\u9000\\u51fa\\uff0c\\u56e0\\u4e3a Tkinter \\u53ef\\u80fd\\u8fd8\\u6ca1\\u5b8c\\u5168\\u521d\\u59cb\\u5316\\n\\n# Windows \\u7cfb\\u7edf\\u7279\\u6709\\u7684\\u5e93\\u5bfc\\u5165\\nif platform.system() == &#039;Windows&#039;:\\n    import winsound\\n    from ctypes import POINTER, cast\\n    from comtypes import CLSCTX_ALL, CoInitialize\\n    from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume\\n\\n# ----------------- Constants (\\u5e38\\u91cf) -----------------\\nDEFAULT_VOLUME = 100\\nDEFAULT_REGION_LEFT = 100\\nDEFAULT_REGION_TOP = 100\\nDEFAULT_REGION_RIGHT = 400\\nDEFAULT_REGION_BOTTOM = 300\\nDEFAULT_DARK_THRESHOLD = 30\\nDEFAULT_DARK_DURATION_SEC = 20 # \\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f\\nDEFAULT_MAX_WAIT_MINUTES = 10 # \\u533a\\u57df\\u68c0\\u6d4b\\u6a21\\u5f0f\\u4e0b\\u6700\\u5927\\u7b49\\u5f85\\u65f6\\u95f4\\nDEFAULT_TIMER_MINUTES = 5\\nDEFAULT_TIMER_TIMES = 90\\n# \\u4fee\\u6539\\u9ed8\\u8ba4\\u54cd\\u94c3\\u6a21\\u5f0f\\u4e3a \\&quot;1\\&quot; (\\u54cd\\u4e00\\u4e0b)\\nDEFAULT_BELL_MODE = \\&quot;1\\&quot; # \\&quot;1\\&quot;, \\&quot;continuous\\&quot;\\nDEFAULT_SPEED_THRESHOLD_KB = 50 # \\u7f51\\u901f\\u9608\\u503c\\uff0cKB\\\/s\\nDEFAULT_LOW_SPEED_DURATION_SEC = 20 # \\u4f4e\\u901f\\u6301\\u7eed\\u65f6\\u95f4\\nDEFAULT_CHECK_INTERVAL_SEC = 2 # \\u7f51\\u901f\\u68c0\\u6d4b\\u95f4\\u9694\\n\\n# \\u65b0\\u589e\\uff1a\\u6301\\u7eed\\u54cd\\u94c3\\u9ed8\\u8ba4\\u65f6\\u957f\\nDEFAULT_CONTINUOUS_BELL_DURATION = 5 # \\u6301\\u7eed\\u54cd\\u94c3\\u6a21\\u5f0f\\u6700\\u957f\\u54cd\\u94c3\\u65f6\\u95f4 (\\u79d2)\\n\\n# \\u5b57\\u4f53\\u8bbe\\u7f6e\\nDEFAULT_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 12)\\nSTATUS_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 12)\\nCOUNTDOWN_FONT = (\\&quot;\\u5b8b\\u4f53\\&quot;, 14)\\n\\n\\n# ----------------- AudioUtils (\\u97f3\\u9891\\u5de5\\u5177) -----------------\\ndef set_system_volume(vol_percent):\\n    \\&quot;\\&quot;\\&quot;\\u8bbe\\u7f6e\\u7cfb\\u7edf\\u4e3b\\u97f3\\u91cf (\\u4ec5\\u9650Windows)\\&quot;\\&quot;\\&quot;\\n    if platform.system() != &#039;Windows&#039;:\\n        return # \\u975eWindows\\u7cfb\\u7edf\\u4e0d\\u5904\\u7406\\u97f3\\u91cf\\u8c03\\u8282\\n    try:\\n        CoInitialize() # \\u521d\\u59cb\\u5316 COM \\u5e93\\uff0c\\u5bf9\\u4e8e pycaw \\u662f\\u5fc5\\u9700\\u7684\\n        devices = AudioUtilities.GetSpeakers()\\n        interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)\\n        volume = cast(interface, POINTER(IAudioEndpointVolume))\\n        vol = float(vol_percent) \\\/ 100.0\\n        volume.SetMasterVolumeLevelScalar(vol, None)\\n    except Exception as e:\\n        print(f\\&quot;[\\u97f3\\u91cf\\u8c03\\u8282\\u5931\\u8d25] {e}\\&quot;)\\n\\ndef play_bell_sound(): # \\u7b80\\u5316\\uff0c\\u4e0d\\u518d\\u4f7f\\u7528index\\u53c2\\u6570\\u6765\\u6539\\u53d8\\u97f3\\u8c03\\n    \\&quot;\\&quot;\\&quot;\\u64ad\\u653e\\u63d0\\u793a\\u97f3 (\\u5355\\u6b21)\\&quot;\\&quot;\\&quot;\\n    if platform.system() == &#039;Windows&#039;:\\n        try:\\n            winsound.Beep(800, 300) # \\u7edf\\u4e00\\u4f7f\\u7528\\u4e00\\u4e2a\\u7b80\\u5355\\u7684\\u8702\\u9e23\\u58f0\\n        except Exception as e:\\n            print(f\\&quot;[\\u64ad\\u653e\\u63d0\\u793a\\u97f3\\u5931\\u8d25] {e}\\&quot;)\\n            # \\u5982\\u679c\\u54cd\\u94c3\\u5931\\u8d25\\uff0c\\u4e0d\\u5e94\\u8be5\\u5bfc\\u81f4\\u7a0b\\u5e8f\\u5d29\\u6e83\\uff0c\\u53ea\\u6253\\u5370\\u9519\\u8bef\\n    else:\\n        # \\u975eWindows\\u7cfb\\u7edf\\u4f7f\\u7528\\u7cfb\\u7edf\\u54cd\\u94c3\\n        os.system(&#039;echo -e \\&quot;\\\\\\\\a\\&quot;&#039;)\\n\\n# ----------------- RegionSelector (\\u533a\\u57df\\u9009\\u62e9\\u5f39\\u7a97) -----------------\\nclass RegionSelector(tk.Toplevel):\\n    def __init__(self, master, callback):\\n        super().__init__(master)\\n        self.callback = callback\\n        self.start_x = None\\n        self.start_y = None\\n        self.rect = None\\n        # \\u8bbe\\u7f6e\\u7a97\\u53e3\\u5168\\u5c4f\\u3001\\u65e0\\u8fb9\\u6846\\u3001\\u534a\\u900f\\u660e\\u3001\\u7f6e\\u9876\\n        self.geometry(f\\&quot;{self.winfo_screenwidth()}x{self.winfo_screenheight()}+0+0\\&quot;)\\n        self.overrideredirect(True)  # \\u53bb\\u6389\\u6807\\u9898\\u680f\\n        self.attributes(&#039;-alpha&#039;, 0.3)  # \\u534a\\u900f\\u660e\\n        self.attributes(&#039;-topmost&#039;, True) # \\u7f6e\\u9876\\n        self.config(bg=&#039;black&#039;)\\n\\n        self.canvas = tk.Canvas(self, cursor=\\&quot;cross\\&quot;, bg=&#039;black&#039;)\\n        self.canvas.pack(fill=tk.BOTH, expand=True)\\n\\n        self.canvas.bind(\\&quot;&lt;ButtonPress-1&gt;\\&quot;, self.on_button_press)\\n        self.canvas.bind(\\&quot;&lt;B1-Motion&gt;\\&quot;, self.on_mouse_move)\\n        self.canvas.bind(\\&quot;&lt;ButtonRelease-1&gt;\\&quot;, self.on_button_release)\\n\\n    def on_button_press(self, event):\\n        self.start_x = self.canvas.canvasx(event.x)\\n        self.start_y = self.canvas.canvasy(event.y)\\n        if self.rect:\\n            self.canvas.delete(self.rect)\\n        self.rect = self.canvas.create_rectangle(self.start_x, self.start_y,\\n                                                 self.start_x, self.start_y,\\n                                                 outline=&#039;red&#039;, width=2)\\n\\n    def on_mouse_move(self, event):\\n        cur_x = self.canvas.canvasx(event.x)\\n        cur_y = self.canvas.canvasy(event.y)\\n        self.canvas.coords(self.rect, self.start_x, self.start_y, cur_x, cur_y)\\n\\n    def on_button_release(self, event):\\n        end_x = self.canvas.canvasx(event.x)\\n        end_y = self.canvas.canvasy(event.y)\\n        left = int(min(self.start_x, end_x))\\n        top = int(min(self.start_y, end_y))\\n        right = int(max(self.start_x, end_x))\\n        bottom = int(max(self.start_y, end_y))\\n\\n        self.callback(left, top, right, bottom)\\n        self.destroy()\\n\\n# ----------------- ConfigManager (\\u914d\\u7f6e\\u7ba1\\u7406\\u5668) -----------------\\nclass ConfigManager:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.config_file = \\&quot;bell_app_config.json\\&quot;\\n\\n    def save_config(self):\\n        config = {\\n            \\&quot;tab_selected\\&quot;: self.app.notebook.index(self.app.notebook.select()),\\n            \\&quot;region_left\\&quot;: self.app.left_var.get(),\\n            \\&quot;region_top\\&quot;: self.app.top_var.get(),\\n            \\&quot;region_right\\&quot;: self.app.right_var.get(),\\n            \\&quot;region_bottom\\&quot;: self.app.bottom_var.get(),\\n            \\&quot;dark_threshold\\&quot;: self.app.dark_threshold_var.get(),\\n            \\&quot;dark_duration_sec\\&quot;: self.app.dark_duration_sec_var.get(),\\n            \\&quot;max_wait_minutes\\&quot;: self.app.max_wait_minutes_var.get(),\\n            \\&quot;timer_minutes\\&quot;: self.app.minutes_var.get(),\\n            \\&quot;timer_times\\&quot;: self.app.times_var.get(),\\n            \\&quot;bell_mode\\&quot;: self.app.mode_var.get(), # \\u4fdd\\u5b58\\u4fee\\u6539\\u540e\\u7684bell_mode\\n            \\&quot;speed_threshold_kb\\&quot;: self.app.speed_threshold_kb_var.get(),\\n            \\&quot;low_speed_duration_sec\\&quot;: self.app.low_speed_duration_sec_var.get(),\\n            \\&quot;check_interval_sec\\&quot;: self.app.check_interval_sec_var.get(),\\n            \\&quot;volume\\&quot;: self.app.volume_var.get(),\\n            \\&quot;continuous_bell_duration\\&quot;: self.app.continuous_bell_duration_var.get()\\n        }\\n        try:\\n            with open(self.config_file, &#039;w&#039;) as f:\\n                json.dump(config, f)\\n        except Exception as e:\\n            print(f\\&quot;\\u4fdd\\u5b58\\u914d\\u7f6e\\u5931\\u8d25: {e}\\&quot;)\\n\\n    def load_config(self):\\n        if os.path.exists(self.config_file):\\n            try:\\n                with open(self.config_file, &#039;r&#039;) as f:\\n                    config = json.load(f)\\n                    # \\u52a0\\u8f7d\\u9009\\u9879\\u5361\\uff0c\\u9ed8\\u8ba4\\u9009\\u4e2d\\u7f51\\u901f\\u68c0\\u6d4b (\\u7d22\\u5f15 2)\\n                    tab_index = config.get(\\&quot;tab_selected\\&quot;, 2)\\n                    self.app.notebook.select(tab_index)\\n\\n                    # \\u52a0\\u8f7d\\u533a\\u57df\\u68c0\\u6d4b\\u914d\\u7f6e\\n                    self.app.left_var.set(config.get(\\&quot;region_left\\&quot;, str(DEFAULT_REGION_LEFT)))\\n                    self.app.top_var.set(config.get(\\&quot;region_top\\&quot;, str(DEFAULT_REGION_TOP)))\\n                    self.app.right_var.set(config.get(\\&quot;region_right\\&quot;, str(DEFAULT_REGION_RIGHT)))\\n                    self.app.bottom_var.set(config.get(\\&quot;region_bottom\\&quot;, str(DEFAULT_REGION_BOTTOM)))\\n                    self.app.dark_threshold_var.set(config.get(\\&quot;dark_threshold\\&quot;, str(DEFAULT_DARK_THRESHOLD)))\\n                    self.app.dark_duration_sec_var.set(config.get(\\&quot;dark_duration_sec\\&quot;, str(DEFAULT_DARK_DURATION_SEC)))\\n                    self.app.max_wait_minutes_var.set(config.get(\\&quot;max_wait_minutes\\&quot;, str(DEFAULT_MAX_WAIT_MINUTES)))\\n                    \\n                    # \\u52a0\\u8f7d\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\u914d\\u7f6e\\n                    self.app.minutes_var.set(config.get(\\&quot;timer_minutes\\&quot;, str(DEFAULT_TIMER_MINUTES)))\\n                    self.app.times_var.set(config.get(\\&quot;timer_times\\&quot;, str(DEFAULT_TIMER_TIMES)))\\n                    \\n                    # \\u52a0\\u8f7d\\u4fee\\u6539\\u540e\\u7684bell_mode\\u548c\\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u957f\\n                    self.app.mode_var.set(config.get(\\&quot;bell_mode\\&quot;, DEFAULT_BELL_MODE)) \\n                    self.app.continuous_bell_duration_var.set(config.get(\\&quot;continuous_bell_duration\\&quot;, str(DEFAULT_CONTINUOUS_BELL_DURATION)))\\n                    \\n                    # \\u52a0\\u8f7d\\u7f51\\u901f\\u68c0\\u6d4b\\u914d\\u7f6e\\n                    self.app.speed_threshold_kb_var.set(config.get(\\&quot;speed_threshold_kb\\&quot;, str(DEFAULT_SPEED_THRESHOLD_KB)))\\n                    self.app.low_speed_duration_sec_var.set(config.get(\\&quot;low_speed_duration_sec\\&quot;, str(DEFAULT_LOW_SPEED_DURATION_SEC)))\\n                    self.app.check_interval_sec_var.set(config.get(\\&quot;check_interval_sec\\&quot;, str(DEFAULT_CHECK_INTERVAL_SEC)))\\n\\n                    # \\u52a0\\u8f7d\\u97f3\\u91cf\\n                    self.app.volume_var.set(config.get(\\&quot;volume\\&quot;, DEFAULT_VOLUME))\\n\\n                    self.app.region_status_label.config(text=f\\&quot;\\u5df2\\u52a0\\u8f7d\\u4e0a\\u6b21\\u533a\\u57df\\uff1a({self.app.left_var.get()},{self.app.top_var.get()},{self.app.right_var.get()},{self.app.bottom_var.get()})\\&quot;)\\n            except Exception as e:\\n                print(f\\&quot;\\u52a0\\u8f7d\\u914d\\u7f6e\\u5931\\u8d25: {e}\\&quot;)\\n                messagebox.showwarning(\\&quot;\\u52a0\\u8f7d\\u914d\\u7f6e\\&quot;, f\\&quot;\\u52a0\\u8f7d\\u5386\\u53f2\\u914d\\u7f6e\\u5931\\u8d25\\uff0c\\u5c06\\u4f7f\\u7528\\u9ed8\\u8ba4\\u8bbe\\u7f6e\\u3002\\\\n\\u9519\\u8bef\\uff1a{e}\\&quot;)\\n\\n# ----------------- Detector Classes (\\u68c0\\u6d4b\\u5668\\u7c7b) -----------------\\n\\nclass RegionColorDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.was_dark_previously = False # \\u533a\\u57df\\u68c0\\u6d4b\\uff1a\\u4e0a\\u6b21\\u662f\\u5426\\u4e3a\\u6697\\u8272\\n        self.dark_start_time = None # \\u533a\\u57df\\u68c0\\u6d4b\\uff1a\\u8bb0\\u5f55\\u533a\\u57df\\u5f00\\u59cb\\u53d8\\u6697\\u7684\\u65f6\\u95f4\\n        self.countdown_start_time = 0 # \\u7528\\u4e8e\\u663e\\u793a\\u5012\\u8ba1\\u65f6\\n\\n    def reset_state(self):\\n        self.was_dark_previously = False\\n        self.dark_start_time = None\\n        self.countdown_start_time = 0\\n\\n    def get_region_brightness(self):\\n        \\&quot;\\&quot;\\&quot;\\n        \\u83b7\\u53d6\\u6307\\u5b9a\\u533a\\u57df\\u7684\\u5c4f\\u5e55\\u622a\\u56fe\\u7684\\u5e73\\u5747\\u4eae\\u5ea6\\u3002\\n        \\&quot;\\&quot;\\&quot;\\n        try:\\n            # bbox \\u4ece app_instance \\u83b7\\u53d6\\n            bbox = (\\n                int(self.app.left_var.get()),\\n                int(self.app.top_var.get()),\\n                int(self.app.right_var.get()),\\n                int(self.app.bottom_var.get())\\n            )\\n            current_img = ImageGrab.grab(bbox=bbox).convert(&#039;L&#039;) # \\u8f6c\\u6362\\u4e3a\\u7070\\u5ea6\\u56fe\\n            mean_brightness = ImageStat.Stat(current_img).mean[0] # \\u83b7\\u53d6\\u5e73\\u5747\\u4eae\\u5ea6 (0-255)\\n            return mean_brightness\\n        except Exception as e:\\n            print(f\\&quot;[\\u622a\\u56fe\\u68c0\\u6d4b\\u5f02\\u5e38] {e}\\&quot;)\\n            self.app.root.after(0, lambda exc=e: self.app.region_status_label.config(text=f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u5f02\\u5e38\\uff1a{exc}\\&quot;, fg=\\&quot;red\\&quot;))\\n            return -1 # \\u8fd4\\u56de\\u4e00\\u4e2a\\u4e0d\\u53ef\\u80fd\\u7684\\u4eae\\u5ea6\\u503c\\u8868\\u793a\\u5f02\\u5e38\\n\\n    def check_condition(self):\\n        \\&quot;\\&quot;\\&quot;\\u68c0\\u67e5\\u533a\\u57df\\u989c\\u8272\\u662f\\u5426\\u6ee1\\u8db3\\u54cd\\u94c3\\u6761\\u4ef6\\&quot;\\&quot;\\&quot;\\n        should_ring = False\\n        status_message = \\&quot;\\&quot;\\n        \\n        dark_threshold = int(self.app.dark_threshold_var.get())\\n        dark_duration_sec = int(self.app.dark_duration_sec_var.get())\\n        max_wait_seconds = int(float(self.app.max_wait_minutes_var.get()) * 60)\\n\\n        current_time = time.time()\\n        elapsed_max_wait_time = int(current_time - self.app.start_cycle_time) # \\u4ece\\u5f53\\u524d\\u5468\\u671f\\u5f00\\u59cb\\u5230\\u73b0\\u5728\\u7684\\u8017\\u65f6\\n\\n        # \\u68c0\\u67e5\\u6574\\u4f53\\u8d85\\u65f6\\uff08\\u4e0e\\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f\\u662f\\u6216\\u7684\\u5173\\u7cfb\\uff09\\n        if elapsed_max_wait_time &gt;= max_wait_seconds:\\n            should_ring = True\\n            status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u8d85\\u65f6\\uff0c\\u5f3a\\u5236\\u54cd\\u94c3\\&quot;\\n            self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;red\\&quot;))\\n            return should_ring, status_message\\n\\n        current_brightness = self.get_region_brightness()\\n        is_current_dark = (current_brightness != -1 and current_brightness &lt;= dark_threshold)\\n\\n        if is_current_dark:\\n            if not self.was_dark_previously: # \\u521a\\u8fdb\\u5165\\u6697\\u8272\\u72b6\\u6001\\n                self.dark_start_time = current_time # \\u5f00\\u59cb\\u8ba1\\u65f6\\n                status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u68c0\\u6d4b\\u5230\\u533a\\u57df\\u53d8\\u6697\\uff0c\\u5f00\\u59cb\\u8ba1\\u65f6...\\&quot;\\n                self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n            else: # \\u6301\\u7eed\\u6697\\u8272\\u4e2d\\n                if self.dark_start_time is not None and (current_time - self.dark_start_time) &gt;= dark_duration_sec:\\n                    should_ring = True\\n                    status_message = \\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u6697\\u8272\\u8fbe\\u5230\\u9608\\u503c\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n                    self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;green\\&quot;))\\n                else:\\n                    duration = 0 if self.dark_start_time is None else (current_time - self.dark_start_time)\\n                    status_message = f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u6697\\u8272\\u4e2d {duration:.1f} \\\/ {dark_duration_sec} \\u79d2\\&quot;\\n                    self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n        else: # \\u533a\\u57df\\u4e0d\\u662f\\u6697\\u8272\\n            self.dark_start_time = None # \\u91cd\\u7f6e\\u6697\\u8272\\u8ba1\\u65f6\\n            status_message = f\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u533a\\u57df\\u6b63\\u5e38 (\\u5f53\\u524d\\u4eae\\u5ea6 {current_brightness:.2f} \\\/ \\u9608\\u503c {dark_threshold})\\&quot;\\n            self.app.root.after(0, lambda: self.app.region_status_label.config(text=status_message, fg=\\&quot;black\\&quot;))\\n        \\n        self.was_dark_previously = is_current_dark\\n        self.countdown_start_time = current_time # update for display\\n        \\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        max_wait_seconds = int(float(self.app.max_wait_minutes_var.get()) * 60)\\n        remaining_time = max_wait_seconds - int(time.time() - self.app.start_cycle_time)\\n        mins, secs = divmod(max(0, remaining_time), 60) # Ensure no negative time display\\n        return f\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a{mins:02d}:{secs:02d}\\&quot;\\n\\nclass NetworkSpeedDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self._last_net_bytes_recv = 0 # \\u4e0a\\u6b21\\u68c0\\u6d4b\\u65f6\\u603b\\u63a5\\u6536\\u5b57\\u8282\\u6570\\n        self._last_net_timestamp = 0 # \\u4e0a\\u6b21\\u68c0\\u6d4b\\u65f6\\u95f4\\u6233\\n        self.low_speed_start_time = None # \\u8bb0\\u5f55\\u4f4e\\u7f51\\u901f\\u5f00\\u59cb\\u7684\\u65f6\\u95f4\\n        self.is_low_speed_currently = False # \\u5f53\\u524d\\u662f\\u5426\\u5904\\u4e8e\\u4f4e\\u7f51\\u901f\\u72b6\\u6001\\n        self.was_low_speed_previously = False # \\u4e0a\\u4e00\\u4e2a\\u68c0\\u6d4b\\u5468\\u671f\\u662f\\u5426\\u5904\\u4e8e\\u4f4e\\u7f51\\u901f\\u72b6\\u6001\\n        self.awaiting_significant_traffic = True # \\u542f\\u52a8\\u65f6\\u7b49\\u5f85\\u5927\\u6d41\\u91cf\\n        self.countdown_start_time = 0 # For display purposes\\n\\n    def reset_state(self):\\n        self._last_net_bytes_recv = 0\\n        self._last_net_timestamp = 0\\n        self.low_speed_start_time = None\\n        self.is_low_speed_currently = False\\n        self.was_low_speed_previously = False\\n        self.awaiting_significant_traffic = True\\n        self.countdown_start_time = 0\\n\\n    def get_network_speed(self):\\n        \\&quot;\\&quot;\\&quot;\\n        \\u4f7f\\u7528 psutil \\u83b7\\u53d6\\u672c\\u5730\\u7f51\\u5361\\u7684\\u603b\\u4e0b\\u8f7d\\u901f\\u5ea6 (KB\\\/s)\\u3002\\n        \\&quot;\\&quot;\\&quot;\\n        try:\\n            current_counters = psutil.net_io_counters() # \\u83b7\\u53d6\\u7cfb\\u7edf\\u6240\\u6709\\u7f51\\u7edc\\u63a5\\u53e3\\u7684\\u603b\\u8ba1\\u6570\\u5668\\n            current_time = time.time()\\n\\n            if self._last_net_timestamp == 0:\\n                self._last_net_bytes_recv = current_counters.bytes_recv\\n                self._last_net_timestamp = current_time\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u521d\\u59cb\\u5316\\u4e2d...\\&quot;, fg=\\&quot;blue\\&quot;))\\n                return 0.0\\n\\n            time_diff = current_time - self._last_net_timestamp\\n            if time_diff &lt;= 0: # \\u907f\\u514d\\u9664\\u4ee5\\u96f6\\u6216\\u8d1f\\u65f6\\u95f4\\n                return 0.0\\n\\n            recv_diff = current_counters.bytes_recv - self._last_net_bytes_recv\\n            \\n            self._last_net_bytes_recv = current_counters.bytes_recv\\n            self._last_net_timestamp = current_time\\n\\n            speed_kbps = (recv_diff \\\/ time_diff) \\\/ 1024\\n            return speed_kbps\\n\\n        except Exception as e:\\n            print(f\\&quot;[\\u7f51\\u901f\\u68c0\\u6d4b\\u5f02\\u5e38] {e}\\&quot;)\\n            self.app.root.after(0, lambda exc=e: self.app.network_status_label.config(text=f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u5f02\\u5e38\\uff1a{exc}\\&quot;, fg=\\&quot;red\\&quot;))\\n            self.app.root.after(0, lambda: self.app.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a\\u68c0\\u6d4b\\u5931\\u8d25\\&quot;, fg=\\&quot;red\\&quot;))\\n            return -1.0 # \\u8fd4\\u56de\\u4e00\\u4e2a\\u8d1f\\u503c\\u8868\\u793a\\u68c0\\u6d4b\\u5931\\u8d25\\n\\n    def check_condition(self):\\n        \\&quot;\\&quot;\\&quot;\\u68c0\\u67e5\\u7f51\\u901f\\u662f\\u5426\\u6ee1\\u8db3\\u54cd\\u94c3\\u6761\\u4ef6\\&quot;\\&quot;\\&quot;\\n        should_ring = False\\n        status_message = \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u4e2d...\\&quot;\\n\\n        speed_threshold_kb = float(self.app.speed_threshold_kb_var.get())\\n        low_speed_duration_sec = int(self.app.low_speed_duration_sec_var.get())\\n        # check_interval_sec is handled in main_app&#039;s run_timer loop, not here.\\n\\n        current_speed = self.get_network_speed()\\n\\n        if current_speed == -1.0: # \\u68c0\\u6d4b\\u5931\\u8d25\\n            status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u68c0\\u6d4b\\u5931\\u8d25\\uff0c\\u91cd\\u8bd5\\u4e2d...\\&quot;\\n            self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;red\\&quot;))\\n            self.app.root.after(0, lambda s=current_speed: self.app.current_speed_label.config(text=f\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n            return False, status_message\\n\\n        # \\u66f4\\u65b0UI\\u663e\\u793a\\u5f53\\u524d\\u901f\\u5ea6\\n        self.app.root.after(0, lambda s=current_speed: self.app.current_speed_label.config(text=f\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a{s:.2f} KB\\\/S\\&quot;))\\n\\n        self.is_low_speed_currently = (current_speed &lt; speed_threshold_kb)\\n\\n        # \\u542f\\u52a8\\u65f6\\u7b49\\u5f85\\u5927\\u6d41\\u91cf\\u903b\\u8f91\\n        if self.awaiting_significant_traffic:\\n            # \\u5982\\u679c\\u5f53\\u524d\\u6709\\u660e\\u663e\\u6d41\\u91cf (\\u6bd4\\u5982\\u9608\\u503c\\u76842\\u500d)\\uff0c\\u5219\\u5f00\\u59cb\\u76d1\\u6d4b\\n            if current_speed &gt;= speed_threshold_kb * 2 and current_speed &gt; 0:\\n                self.awaiting_significant_traffic = False\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u5df2\\u68c0\\u6d4b\\u5230\\u6d41\\u91cf\\uff0c\\u5f00\\u59cb\\u76d1\\u6d4b...\\&quot;, fg=\\&quot;blue\\&quot;))\\n                return False, status_message # \\u4e0d\\u54cd\\u94c3\\uff0c\\u7ee7\\u7eed\\u76d1\\u6d4b\\n            else:\\n                status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7b49\\u5f85\\u6709\\u660e\\u663e\\u6d41\\u91cf\\u65f6\\u5f00\\u59cb\\u76d1\\u6d4b...\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;gray\\&quot;))\\n                return False, status_message # \\u8fd8\\u5728\\u7b49\\u5f85\\u6d41\\u91cf\\n\\n        # \\u5224\\u65ad\\u662f\\u5426\\u5e94\\u8be5\\u54cd\\u94c3\\u7684\\u903b\\u8f91\\n        if self.is_low_speed_currently:\\n            if not self.was_low_speed_previously:\\n                self.low_speed_start_time = time.time() # \\u521a\\u8fdb\\u5165\\u4f4e\\u901f\\u72b6\\u6001\\uff0c\\u8bb0\\u5f55\\u5f00\\u59cb\\u65f6\\u95f4\\n                status_message = f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u8fdb\\u5165\\u4f4e\\u901f\\u72b6\\u6001\\uff0c\\u6301\\u7eed {0:.1f} \\\/ {low_speed_duration_sec} \\u79d2\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n            else: # \\u6301\\u7eed\\u4f4e\\u901f\\u4e2d\\n                duration = time.time() - self.low_speed_start_time\\n                status_message = f\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u6301\\u7eed\\u4f4e\\u901f\\u4e2d {duration:.1f} \\\/ {low_speed_duration_sec} \\u79d2\\&quot;\\n                self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;darkorange\\&quot;))\\n                if duration &gt;= low_speed_duration_sec:\\n                    should_ring = True\\n                    status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7f51\\u901f\\u6301\\u7eed\\u4f4e\\u4e8e\\u9608\\u503c\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n                    self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;green\\&quot;))\\n        else: # \\u5f53\\u524d\\u4e0d\\u662f\\u4f4e\\u901f\\uff0c\\u91cd\\u7f6e\\u8ba1\\u65f6\\n            self.low_speed_start_time = None\\n            status_message = \\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7f51\\u901f\\u6b63\\u5e38\\&quot;\\n            self.app.root.after(0, lambda: self.app.network_status_label.config(text=status_message, fg=\\&quot;black\\&quot;))\\n        \\n        self.was_low_speed_previously = self.is_low_speed_currently # \\u66f4\\u65b0\\u72b6\\u6001\\n        self.countdown_start_time = time.time() # update for display\\n        \\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        # \\u5bf9\\u4e8e\\u7f51\\u901f\\u68c0\\u6d4b\\uff0c\\u4e3b\\u8981\\u663e\\u793a\\u201c\\u68c0\\u6d4b\\u4e2d...\\u201d\\n        return \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u4e2d...\\&quot;\\n\\nclass TimerDetector:\\n    def __init__(self, app_instance):\\n        self.app = app_instance\\n        self.countdown_start_time = 0 # \\u8bb0\\u5f55\\u6bcf\\u4e2a\\u5468\\u671f\\u7684\\u5f00\\u59cb\\u65f6\\u95f4\\n\\n    def reset_state(self):\\n        self.countdown_start_time = 0\\n\\n    def check_condition(self):\\n        \\&quot;\\&quot;\\&quot;\\u68c0\\u67e5\\u56fa\\u5b9a\\u65f6\\u95f4\\u662f\\u5426\\u6ee1\\u8db3\\u54cd\\u94c3\\u6761\\u4ef6\\&quot;\\&quot;\\&quot;\\n        should_ring = False\\n        status_message = \\&quot;\\&quot;\\n        \\n        interval_seconds = int(float(self.app.minutes_var.get()) * 60)\\n        \\n        current_time = time.time()\\n        \\n        if self.countdown_start_time == 0: # \\u5468\\u671f\\u521a\\u5f00\\u59cb\\n            self.countdown_start_time = current_time\\n        \\n        elapsed_time = int(current_time - self.countdown_start_time)\\n        \\n        if elapsed_time &gt;= interval_seconds:\\n            should_ring = True\\n            self.countdown_start_time = current_time # \\u54cd\\u94c3\\u540e\\u91cd\\u65b0\\u5f00\\u59cb\\u8ba1\\u65f6\\n            status_message = \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\uff1a\\u65f6\\u95f4\\u5230\\uff0c\\u54cd\\u94c3\\uff01\\&quot;\\n        else:\\n            status_message = \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\uff1a\\u7b49\\u5f85\\u4e2d...\\&quot;\\n            \\n        return should_ring, status_message\\n\\n    def get_display_info(self):\\n        interval_seconds = int(float(self.app.minutes_var.get()) * 60)\\n        remaining_time = interval_seconds - int(time.time() - self.countdown_start_time)\\n        mins, secs = divmod(max(0, remaining_time), 60)\\n        return f\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a{mins:02d}:{secs:02d}\\&quot;\\n\\n# ----------------- MainApp (\\u4e3b\\u7a0b\\u5e8f) -----------------\\nclass BellApp:\\n    def __init__(self, root):\\n        self.root = root\\n        self.root.title(\\&quot;\\u667a\\u80fd\\u54cd\\u94c3\\u5668\\&quot;)\\n        self.root.geometry(\\&quot;550x500\\&quot;) # \\u8c03\\u6574\\u7a97\\u53e3\\u9ad8\\u5ea6\\n\\n        self.running = False # \\u6807\\u8bb0\\u4e3b\\u5faa\\u73af\\u662f\\u5426\\u6b63\\u5728\\u8fd0\\u884c\\n        self.reset_flag = False # \\u6807\\u8bb0\\u662f\\u5426\\u9700\\u8981\\u91cd\\u7f6e\\n        self.stop_flag = False # \\u6807\\u8bb0\\u662f\\u5426\\u9700\\u8981\\u505c\\u6b62\\u4e3b\\u5faa\\u73af\\n\\n        self.volume_var = tk.IntVar(value=DEFAULT_VOLUME) # \\u97f3\\u91cf\\u53d8\\u91cf\\n        self.waiting_for_user_after_bell = False # \\u533a\\u57df\\u68c0\\u6d4b\\\/\\u7f51\\u901f\\u68c0\\u6d4b\\uff1a\\u54cd\\u94c3\\u540e\\u662f\\u5426\\u6b63\\u5728\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\n\\n        self.user_active_event = threading.Event() # \\u7528\\u6237\\u6d3b\\u52a8\\u4e8b\\u4ef6\\uff0c\\u7528\\u4e8e\\u8de8\\u7ebf\\u7a0b\\u901a\\u77e5\\n        self.listener_mouse = None # pynput \\u9f20\\u6807\\u76d1\\u542c\\u5668\\u5b9e\\u4f8b\\n        self.listener_keyboard = None # pynput \\u952e\\u76d8\\u76d1\\u542c\\u5668\\u5b9e\\u4f8b\\n\\n        self.config_manager = ConfigManager(self) # \\u914d\\u7f6e\\u7ba1\\u7406\\u5668\\u5b9e\\u4f8b\\n\\n        # \\u68c0\\u6d4b\\u5668\\u5b9e\\u4f8b\\n        self.region_detector = RegionColorDetector(self)\\n        self.network_detector = NetworkSpeedDetector(self)\\n        self.timer_detector = TimerDetector(self)\\n        self.active_detector = None # \\u5f53\\u524d\\u6fc0\\u6d3b\\u7684\\u68c0\\u6d4b\\u5668\\n        self.start_cycle_time = 0 # \\u7528\\u4e8e\\u8bb0\\u5f55\\u5f53\\u524d\\u5faa\\u73af\\u7684\\u5f00\\u59cb\\u65f6\\u95f4\\uff0c\\u4f9b\\u68c0\\u6d4b\\u5668\\u8ba1\\u7b97\\u5012\\u8ba1\\u65f6\\n\\n        # --- Notebook (\\u9009\\u9879\\u5361) ---\\n        self.notebook = ttk.Notebook(root)\\n        self.notebook.pack(pady=5, expand=True, fill=\\&quot;both\\&quot;)\\n\\n        # --- \\u9009\\u9879\\u53611: \\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3 ---\\n        self.tab_timer = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_timer, text=\\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;)\\n\\n        # --- \\u9009\\u9879\\u53612: \\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b ---\\n        self.tab_region = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_region, text=\\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;)\\n\\n        # --- \\u9009\\u9879\\u53613: \\u7f51\\u901f\\u68c0\\u6d4b ---\\n        self.tab_network = tk.Frame(self.notebook)\\n        self.notebook.add(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;)\\n\\n        # --- \\u54cd\\u94c3\\u6a21\\u5f0f\\u7edf\\u4e00\\u9009\\u9879\\u5361 ---\\n        bell_mode_frame = tk.LabelFrame(root, text=\\&quot;\\u54cd\\u94c3\\u6a21\\u5f0f\\&quot;, font=DEFAULT_FONT)\\n        bell_mode_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n\\n        self.mode_var = tk.StringVar(value=DEFAULT_BELL_MODE) # \\u9ed8\\u8ba4\\u4e3a \\&quot;1\\&quot; (\\u54cd\\u4e00\\u4e0b)\\n        tk.Radiobutton(bell_mode_frame, text=\\&quot;\\u54cd\\u4e00\\u4e0b\\&quot;, variable=self.mode_var, value=\\&quot;1\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n        tk.Radiobutton(bell_mode_frame, text=\\&quot;\\u6301\\u7eed\\u54cd\\u94c3\\&quot;, variable=self.mode_var, value=\\&quot;continuous\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n        \\n        # \\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u957f\\u8bbe\\u7f6e\\n        tk.Label(bell_mode_frame, text=\\&quot;\\u6700\\u957f (\\u79d2)\\uff1a\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n        self.continuous_bell_duration_var = tk.StringVar(value=str(DEFAULT_CONTINUOUS_BELL_DURATION))\\n        tk.Entry(bell_mode_frame, textvariable=self.continuous_bell_duration_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;, padx=5)\\n\\n        # --- \\u9009\\u9879\\u53611: \\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\u5185\\u5bb9 ---\\n        time_frame = tk.Frame(self.tab_timer)\\n        time_frame.pack(pady=5)\\n        tk.Label(time_frame, text=\\&quot;\\u6bcf\\u9694\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0)\\n        self.minutes_var = tk.StringVar(value=str(DEFAULT_TIMER_MINUTES))\\n        tk.Entry(time_frame, textvariable=self.minutes_var, width=5, font=DEFAULT_FONT).grid(row=0, column=1)\\n        tk.Label(time_frame, text=\\&quot;\\u5206\\u949f    \\u5171\\u54cd\\u94c3\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2)\\n        self.times_var = tk.StringVar(value=str(DEFAULT_TIMER_TIMES))\\n        tk.Entry(time_frame, textvariable=self.times_var, width=5, font=DEFAULT_FONT).grid(row=0, column=3)\\n        tk.Label(time_frame, text=\\&quot;\\u6b21\\&quot;, font=DEFAULT_FONT).grid(row=0, column=4)\\n\\n\\n        # --- \\u9009\\u9879\\u53612: \\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\u5185\\u5bb9 ---\\n        region_frame = tk.LabelFrame(self.tab_region, text=\\&quot;\\u5c4f\\u5e55\\u533a\\u57df\\u5750\\u6807 (\\u50cf\\u7d20)\\&quot;, font=DEFAULT_FONT)\\n        region_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n\\n        tk.Label(region_frame, text=\\&quot;\\u5de6\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0)\\n        self.left_var = tk.StringVar(value=str(DEFAULT_REGION_LEFT))\\n        tk.Entry(region_frame, textvariable=self.left_var, width=6, font=DEFAULT_FONT).grid(row=0, column=1)\\n        tk.Label(region_frame, text=\\&quot;\\u4e0a\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2)\\n        self.top_var = tk.StringVar(value=str(DEFAULT_REGION_TOP))\\n        tk.Entry(region_frame, textvariable=self.top_var, width=6, font=DEFAULT_FONT).grid(row=0, column=3)\\n        tk.Label(region_frame, text=\\&quot;\\u53f3\\&quot;, font=DEFAULT_FONT).grid(row=0, column=4)\\n        self.right_var = tk.StringVar(value=str(DEFAULT_REGION_RIGHT))\\n        tk.Entry(region_frame, textvariable=self.right_var, width=6, font=DEFAULT_FONT).grid(row=0, column=5)\\n        tk.Label(region_frame, text=\\&quot;\\u4e0b\\&quot;, font=DEFAULT_FONT).grid(row=0, column=6)\\n        self.bottom_var = tk.StringVar(value=str(DEFAULT_REGION_BOTTOM))\\n        tk.Entry(region_frame, textvariable=self.bottom_var, width=6, font=DEFAULT_FONT).grid(row=0, column=7)\\n\\n        self.select_region_btn = tk.Button(region_frame, text=\\&quot;\\u6846\\u9009\\u533a\\u57df\\&quot;, font=DEFAULT_FONT, command=self.open_region_selector)\\n        self.select_region_btn.grid(row=1, column=0, columnspan=8, pady=5, sticky=\\&quot;we\\&quot;)\\n        \\n        dark_threshold_frame = tk.Frame(region_frame)\\n        dark_threshold_frame.grid(row=2, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(dark_threshold_frame, text=\\&quot;\\u9ed1\\u6697\\u9608\\u503c (0-255\\uff0c\\u503c\\u8d8a\\u5c0f\\u8d8a\\u9ed1)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_threshold_var = tk.StringVar(value=str(DEFAULT_DARK_THRESHOLD))\\n        tk.Entry(dark_threshold_frame, textvariable=self.dark_threshold_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        \\n        dark_duration_frame = tk.Frame(region_frame)\\n        dark_duration_frame.grid(row=3, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(dark_duration_frame, text=\\&quot;\\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f (\\u79d2\\uff0c\\u9ed8\\u8ba420)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.dark_duration_sec_var = tk.StringVar(value=str(DEFAULT_DARK_DURATION_SEC))\\n        tk.Entry(dark_duration_frame, textvariable=self.dark_duration_sec_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n\\n        max_wait_time_frame = tk.Frame(region_frame)\\n        max_wait_time_frame.grid(row=4, column=0, columnspan=8, pady=5, sticky=\\&quot;w\\&quot;)\\n        tk.Label(max_wait_time_frame, text=\\&quot;\\u6700\\u5927\\u7b49\\u5f85\\u65f6\\u95f4 (\\u5206\\u949f\\uff0c\\u9ed8\\u8ba410)\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.max_wait_minutes_var = tk.StringVar(value=str(DEFAULT_MAX_WAIT_MINUTES))\\n        tk.Entry(max_wait_time_frame, textvariable=self.max_wait_minutes_var, width=5, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n\\n        self.region_status_label = tk.Label(self.tab_region, text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;, font=STATUS_FONT)\\n        self.region_status_label.pack(pady=2)\\n\\n        # --- \\u9009\\u9879\\u53613: \\u7f51\\u901f\\u68c0\\u6d4b\\u5185\\u5bb9 ---\\n        net_speed_frame = tk.LabelFrame(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u8bbe\\u7f6e\\&quot;, font=DEFAULT_FONT)\\n        net_speed_frame.pack(padx=10, pady=5, fill=\\&quot;x\\&quot;)\\n\\n        tk.Label(net_speed_frame, text=\\&quot;\\u4e0b\\u8f7d\\u901f\\u5ea6\\u5c0f\\u4e8e\\&quot;, font=DEFAULT_FONT).grid(row=0, column=0, pady=5)\\n        self.speed_threshold_kb_var = tk.StringVar(value=str(DEFAULT_SPEED_THRESHOLD_KB))\\n        tk.Entry(net_speed_frame, textvariable=self.speed_threshold_kb_var, width=8, font=DEFAULT_FONT).grid(row=0, column=1, pady=5)\\n        tk.Label(net_speed_frame, text=\\&quot;KB\\\/S\\&quot;, font=DEFAULT_FONT).grid(row=0, column=2, pady=5)\\n        \\n        tk.Label(net_speed_frame, text=\\&quot;\\u5e76\\u6301\\u7eed\\&quot;, font=DEFAULT_FONT).grid(row=1, column=0, pady=5)\\n        self.low_speed_duration_sec_var = tk.StringVar(value=str(DEFAULT_LOW_SPEED_DURATION_SEC))\\n        tk.Entry(net_speed_frame, textvariable=self.low_speed_duration_sec_var, width=8, font=DEFAULT_FONT).grid(row=1, column=1, pady=5)\\n        tk.Label(net_speed_frame, text=\\&quot;\\u79d2\\u65f6\\u54cd\\u94c3\\&quot;, font=DEFAULT_FONT).grid(row=1, column=2, pady=5)\\n\\n        tk.Label(net_speed_frame, text=\\&quot;\\u6bcf\\u9694\\&quot;, font=DEFAULT_FONT).grid(row=2, column=0, pady=5)\\n        self.check_interval_sec_var = tk.StringVar(value=str(DEFAULT_CHECK_INTERVAL_SEC))\\n        tk.Entry(net_speed_frame, textvariable=self.check_interval_sec_var, width=8, font=DEFAULT_FONT).grid(row=2, column=1, pady=5)\\n        tk.Label(net_speed_frame, text=\\&quot;\\u79d2\\u68c0\\u6d4b\\u4e00\\u6b21\\&quot;, font=DEFAULT_FONT).grid(row=2, column=2, pady=5)\\n\\n        self.network_status_label = tk.Label(self.tab_network, text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;, font=STATUS_FONT)\\n        self.network_status_label.pack(pady=2)\\n        self.current_speed_label = tk.Label(self.tab_network, text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;, font=STATUS_FONT, fg=\\&quot;darkgreen\\&quot;)\\n        self.current_speed_label.pack(pady=2)\\n\\n        # --- \\u5171\\u540c\\u90e8\\u5206\\uff1a\\u97f3\\u91cf\\u8c03\\u8282\\u548c\\u63a7\\u5236\\u6309\\u94ae\\u3001\\u72b6\\u6001\\u663e\\u793a ---\\n        vol_frame = tk.Frame(root)\\n        vol_frame.pack(pady=5)\\n        tk.Label(vol_frame, text=\\&quot;\\u5168\\u5c40\\u97f3\\u91cf\\uff1a\\&quot;, font=DEFAULT_FONT).pack(side=\\&quot;left\\&quot;)\\n        self.volume_slider = tk.Scale(vol_frame, from_=0, to=100, orient=\\&quot;horizontal\\&quot;,\\n                                         variable=self.volume_var, length=200)\\n        self.volume_slider.pack(side=\\&quot;left\\&quot;)\\n\\n        btn_frame = tk.Frame(root)\\n        btn_frame.pack(pady=5)\\n        self.start_stop_btn = tk.Button(btn_frame, text=\\&quot;\\u5f00\\u59cb\\&quot;, command=self.toggle_start_stop, font=DEFAULT_FONT, width=10)\\n        self.start_stop_btn.grid(row=0, column=0, padx=5)\\n        tk.Button(btn_frame, text=\\&quot;\\u91cd\\u65b0\\u5f00\\u59cb\\&quot;, command=self.reset, font=DEFAULT_FONT, width=10).grid(row=0, column=1, padx=5)\\n\\n        # \\u72b6\\u6001\\u663e\\u793a\\n        self.countdown_label = tk.Label(root, text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;, font=COUNTDOWN_FONT, fg=\\&quot;blue\\&quot;)\\n        self.countdown_label.pack(pady=2)\\n        self.status_label = tk.Label(root, text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;, font=STATUS_FONT)\\n        self.status_label.pack(pady=2)\\n\\n        # \\u52a0\\u8f7d\\u4e0a\\u6b21\\u4fdd\\u5b58\\u7684\\u914d\\u7f6e\\n        self.config_manager.load_config()\\n\\n        # \\u7ed1\\u5b9a\\u9009\\u9879\\u5361\\u5207\\u6362\\u4e8b\\u4ef6\\uff0c\\u4ee5\\u4fbf\\u5728\\u5207\\u6362\\u65f6\\u66f4\\u65b0\\u72b6\\u6001\\u6216\\u6e05\\u7406\\n        self.notebook.bind(\\&quot;&lt;&lt;NotebookTabChanged&gt;&gt;\\&quot;, self.on_tab_changed)\\n\\n    def on_tab_changed(self, event):\\n        \\&quot;\\&quot;\\&quot;\\u9009\\u9879\\u5361\\u5207\\u6362\\u65f6\\u8c03\\u7528\\&quot;\\&quot;\\&quot;\\n        # \\u5207\\u6362\\u9009\\u9879\\u5361\\u65f6\\uff0c\\u5982\\u679c\\u6b63\\u5728\\u8fd0\\u884c\\uff0c\\u76f4\\u63a5\\u505c\\u6b62\\n        if self.running:\\n            self.stop()\\n            \\n        # \\u5207\\u6362\\u9009\\u9879\\u5361\\u65f6\\u91cd\\u7f6e\\u6240\\u6709\\u72b6\\u6001\\u663e\\u793a\\u548c\\u5185\\u90e8\\u6807\\u5fd7\\n        self.countdown_label.config(text=\\&quot;\\u5f53\\u524d\\u5012\\u8ba1\\u65f6\\uff1a--:--\\&quot;)\\n        self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;)\\n        self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;)\\n        self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u5f00\\u59cb\\&quot;)\\n        self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;)\\n\\n        self.waiting_for_user_after_bell = False\\n\\n        # \\u91cd\\u7f6e\\u6240\\u6709\\u68c0\\u6d4b\\u5668\\u7684\\u72b6\\u6001\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n\\n    def open_region_selector(self):\\n        def callback(l, t, r, b):\\n            self.left_var.set(str(l))\\n            self.top_var.set(str(t))\\n            self.right_var.set(str(r))\\n            self.bottom_var.set(str(b))\\n            self.region_status_label.config(text=f\\&quot;\\u533a\\u57df\\u5750\\u6807\\u8bbe\\u7f6e\\u4e3a\\uff1a({l},{t},{r},{b})\\&quot;)\\n            self.config_manager.save_config() # \\u6846\\u9009\\u540e\\u4fdd\\u5b58\\u914d\\u7f6e\\n        RegionSelector(self.root, callback)\\n\\n    def on_user_active(self, *args):\\n        \\&quot;\\&quot;\\&quot;\\n        \\u5f53\\u9f20\\u6807\\u6216\\u952e\\u76d8\\u6709\\u4efb\\u4f55\\u64cd\\u4f5c\\u65f6\\uff0c\\u8bbe\\u7f6e\\u7528\\u6237\\u6d3b\\u52a8\\u4e8b\\u4ef6\\u3002\\n        \\u8fd9\\u4e2a\\u51fd\\u6570\\u4f1a\\u88ab pynput \\u76d1\\u542c\\u5668\\u5728\\u4efb\\u610f\\u4f4d\\u7f6e\\u7684\\u9f20\\u6807\\u6216\\u952e\\u76d8\\u64cd\\u4f5c\\u65f6\\u8c03\\u7528\\u3002\\n        \\&quot;\\&quot;\\&quot;\\n        self.user_active_event.set()\\n\\n    def toggle_start_stop(self):\\n        \\&quot;\\&quot;\\&quot;\\u5408\\u5e76\\u7684\\u5f00\\u59cb\\\/\\u505c\\u6b62\\u6309\\u94ae\\u7684\\u903b\\u8f91\\&quot;\\&quot;\\&quot;\\n        if self.running:\\n            self.stop()\\n        else:\\n            self.start()\\n\\n    def start(self):\\n        if self.running: # \\u5982\\u679c\\u5df2\\u7ecf\\u5728\\u8fd0\\u884c\\uff0c\\u5219\\u4e0d\\u505a\\u4efb\\u4f55\\u64cd\\u4f5c\\n            return\\n        \\n        current_tab_name = self.notebook.tab(self.notebook.select(), \\&quot;text\\&quot;) # \\u83b7\\u53d6\\u5f53\\u524d\\u9009\\u4e2d\\u7684\\u9009\\u9879\\u5361\\u6587\\u672c\\n        \\n        try:\\n            self.total_times = int(self.times_var.get()) # \\u603b\\u54cd\\u94c3\\u6b21\\u6570\\n            if self.total_times &lt;= 0:\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u603b\\u54cd\\u94c3\\u6b21\\u6570\\u5fc5\\u987b\\u5927\\u4e8e0\\u3002\\&quot;)\\n                return\\n\\n            # \\u9a8c\\u8bc1\\u97f3\\u91cf\\n            volume_val = self.volume_var.get()\\n            if not (0 &lt;= volume_val &lt;= 100):\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u97f3\\u91cf\\u5fc5\\u987b\\u57280\\u5230100\\u4e4b\\u95f4\\u3002\\&quot;)\\n                return\\n\\n            # \\u9a8c\\u8bc1\\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u957f (\\u5bf9\\u6240\\u6709\\u6a21\\u5f0f\\u90fd\\u53ef\\u89c1\\uff0c\\u4f46\\u53ea\\u5728\\u6301\\u7eed\\u54cd\\u94c3\\u6a21\\u5f0f\\u4e0b\\u903b\\u8f91\\u751f\\u6548)\\n            continuous_bell_duration = int(self.continuous_bell_duration_var.get())\\n            if continuous_bell_duration &lt;= 0:\\n                messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u957f\\u5fc5\\u987b\\u5927\\u4e8e0\\u79d2\\u3002\\&quot;)\\n                return\\n\\n\\n            if current_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                self.active_detector = self.region_detector\\n                # \\u9a8c\\u8bc1\\u533a\\u57df\\u5750\\u6807\\n                _l, _t, _r, _b = int(self.left_var.get()), int(self.top_var.get()), \\\\\\n                                 int(self.right_var.get()), int(self.bottom_var.get())\\n                if _l &gt;= _r or _t &gt;= _b:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u533a\\u57df\\u5750\\u6807\\u8bbe\\u7f6e\\u6709\\u8bef\\uff0c\\u53f3\\u5750\\u6807\\u5fc5\\u987b\\u5927\\u4e8e\\u5de6\\u5750\\u6807\\uff0c\\u4e0b\\u5750\\u6807\\u5fc5\\u987b\\u5927\\u4e8e\\u4e0a\\u5750\\u6807\\u3002\\&quot;)\\n                    return\\n                dark_threshold = int(self.dark_threshold_var.get())\\n                if not (0 &lt;= dark_threshold &lt;= 255):\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u9ed1\\u6697\\u9608\\u503c\\u5fc5\\u987b\\u57280\\u5230255\\u4e4b\\u95f4\\u3002\\&quot;)\\n                    return\\n                dark_duration_sec = int(self.dark_duration_sec_var.get())\\n                if dark_duration_sec &lt; 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u6301\\u7eed\\u6697\\u8272\\u65f6\\u957f\\u4e0d\\u80fd\\u4e3a\\u8d1f\\u6570\\u3002\\&quot;)\\n                    return\\n                max_wait_minutes = float(self.max_wait_minutes_var.get())\\n                if max_wait_minutes &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u533a\\u57df\\u68c0\\u6d4b\\u6a21\\u5f0f\\u4e0b\\u7684\\u6700\\u5927\\u7b49\\u5f85\\u65f6\\u95f4\\u5fc5\\u987b\\u5927\\u4e8e0\\u5206\\u949f\\u3002\\&quot;)\\n                    return\\n                \\n                # \\u5728\\u533a\\u57df\\u68c0\\u6d4b\\u6a21\\u5f0f\\u5f00\\u59cb\\u65f6\\uff0c\\u91cd\\u7f6e\\u4e0a\\u6b21\\u6697\\u8272\\u72b6\\u6001\\u548c\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\n                self.region_detector.reset_state()\\n                self.waiting_for_user_after_bell = False\\n\\n            elif current_tab_name == \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;:\\n                self.active_detector = self.timer_detector\\n                interval_minutes = float(self.minutes_var.get())\\n                if interval_minutes &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\u6a21\\u5f0f\\u4e0b\\u7684\\u95f4\\u9694\\u65f6\\u95f4\\u5fc5\\u987b\\u5927\\u4e8e0\\u5206\\u949f\\u3002\\&quot;)\\n                    return\\n                \\n                self.waiting_for_user_after_bell = False\\n            \\n            elif current_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                self.active_detector = self.network_detector\\n                speed_threshold_kb = float(self.speed_threshold_kb_var.get())\\n                low_speed_duration_sec = int(self.low_speed_duration_sec_var.get())\\n                check_interval_sec = int(self.check_interval_sec_var.get())\\n\\n                if speed_threshold_kb &lt;= 0 or low_speed_duration_sec &lt;= 0 or check_interval_sec &lt;= 0:\\n                    messagebox.showerror(\\&quot;\\u8f93\\u5165\\u9519\\u8bef\\&quot;, \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\u7684\\u6240\\u6709\\u8bbe\\u7f6e\\u503c\\u90fd\\u5fc5\\u987b\\u5927\\u4e8e0\\u3002\\&quot;)\\n                    return\\n                if check_interval_sec &gt; low_speed_duration_sec:\\n                     messagebox.showwarning(\\&quot;\\u8bbe\\u7f6e\\u5efa\\u8bae\\&quot;, \\&quot;\\u68c0\\u6d4b\\u95f4\\u9694\\u65f6\\u95f4\\u901a\\u5e38\\u5e94\\u5c0f\\u4e8e\\u4f4e\\u901f\\u6301\\u7eed\\u65f6\\u95f4\\uff0c\\u5426\\u5219\\u53ef\\u80fd\\u65e0\\u6cd5\\u51c6\\u786e\\u68c0\\u6d4b\\u6301\\u7eed\\u4f4e\\u901f\\u3002\\&quot;)\\n                \\n                self.network_detector.reset_state() # \\u521d\\u59cb\\u5316\\u7f51\\u901f\\u68c0\\u6d4b\\u72b6\\u6001\\n                self.network_detector.awaiting_significant_traffic = True # \\u542f\\u52a8\\u65f6\\u7b49\\u5f85\\u5927\\u6d41\\u91cf\\n                self.waiting_for_user_after_bell = False\\n\\n        except ValueError as e:\\n            messagebox.showerror(\\&quot;\\u683c\\u5f0f\\u9519\\u8bef\\&quot;, f\\&quot;\\u8bf7\\u8f93\\u5165\\u6709\\u6548\\u7684\\u6570\\u5b57\\uff0c\\u6216\\u68c0\\u67e5\\u8f93\\u5165\\u8303\\u56f4\\u3002\\\\n\\u9519\\u8bef\\uff1a{e}\\&quot;)\\n            return\\n        \\n        if self.active_detector is None:\\n            messagebox.showerror(\\&quot;\\u6a21\\u5f0f\\u9009\\u62e9\\&quot;, \\&quot;\\u8bf7\\u9009\\u62e9\\u4e00\\u4e2a\\u8fd0\\u884c\\u6a21\\u5f0f\\u3002\\&quot;)\\n            return\\n\\n        self.current_count = 1 # \\u5f53\\u524d\\u54cd\\u94c3\\u6b21\\u6570\\n        self.running = True # \\u8bbe\\u7f6e\\u8fd0\\u884c\\u6807\\u5fd7\\n        self.stop_flag = False # \\u91cd\\u7f6e\\u505c\\u6b62\\u6807\\u5fd7\\n        self.reset_flag = False # \\u91cd\\u7f6e\\u91cd\\u7f6e\\u6807\\u5fd7\\n        self.user_active_event.clear() # \\u5f00\\u59cb\\u524d\\u6e05\\u9664\\u7528\\u6237\\u6d3b\\u52a8\\u6807\\u5fd7\\n        \\n        # \\u5728\\u542f\\u52a8\\u65b0\\u7684\\u76d1\\u542c\\u5668\\u4e4b\\u524d\\uff0c\\u786e\\u4fdd\\u505c\\u6b62\\u5e76\\u6e05\\u7406\\u6240\\u6709\\u65e7\\u7684\\u76d1\\u542c\\u5668\\n        self.stop_listeners()\\n\\n        # \\u91cd\\u65b0\\u521b\\u5efa\\u5e76\\u542f\\u52a8\\u76d1\\u542c\\u5668\\uff0c\\u8bbe\\u7f6e\\u4e3a\\u5b88\\u62a4\\u7ebf\\u7a0b\\n        self.listener_mouse = mouse.Listener(on_move=self.on_user_active,\\n                                             on_click=self.on_user_active,\\n                                             on_scroll=self.on_user_active)\\n        self.listener_keyboard = keyboard.Listener(on_press=self.on_user_active)\\n        \\n        self.listener_mouse.daemon = True\\n        self.listener_keyboard.daemon = True\\n        self.listener_mouse.start()\\n        self.listener_keyboard.start()\\n\\n        # \\u66f4\\u65b0\\u6309\\u94ae\\u6587\\u672c\\n        self.start_stop_btn.config(text=\\&quot;\\u505c\\u6b62\\&quot;)\\n\\n        # \\u5728\\u5355\\u72ec\\u7684\\u7ebf\\u7a0b\\u4e2d\\u8fd0\\u884c\\u4e3b\\u8ba1\\u65f6\\u903b\\u8f91\\n        threading.Thread(target=self.run_timer, args=(current_tab_name,), daemon=True).start()\\n        self.config_manager.save_config() # \\u5f00\\u59cb\\u65f6\\u4fdd\\u5b58\\u4e00\\u6b21\\u914d\\u7f6e\\n\\n    def stop_listeners(self):\\n        \\&quot;\\&quot;\\&quot;\\u5b89\\u5168\\u5730\\u505c\\u6b62\\u5e76\\u6e05\\u9664\\u6240\\u6709pynput\\u76d1\\u542c\\u5668\\&quot;\\&quot;\\&quot;\\n        if self.listener_mouse is not None and self.listener_mouse.is_alive():\\n            try:\\n                self.listener_mouse.stop()\\n                self.listener_mouse.join(timeout=1.0)\\n            except RuntimeError:\\n                pass # \\u7ebf\\u7a0b\\u53ef\\u80fd\\u5df2\\u7ecf\\u505c\\u6b62\\uff0c\\u5ffd\\u7565\\u6b64\\u9519\\u8bef\\n            finally:\\n                self.listener_mouse = None\\n        \\n        if self.listener_keyboard is not None and self.listener_keyboard.is_alive():\\n            try:\\n                self.listener_keyboard.stop()\\n                self.listener_keyboard.join(timeout=1.0)\\n            except RuntimeError:\\n                pass # \\u7ebf\\u7a0b\\u53ef\\u80fd\\u5df2\\u7ecf\\u505c\\u6b62\\uff0c\\u5ffd\\u7565\\u6b64\\u9519\\u8bef\\n            finally:\\n                self.listener_keyboard = None\\n\\n    def reset(self):\\n        \\&quot;\\&quot;\\&quot;\\u624b\\u52a8\\u91cd\\u7f6e\\u7a0b\\u5e8f\\u72b6\\u6001\\uff0c\\u91cd\\u65b0\\u5f00\\u59cb\\u8ba1\\u65f6\\&quot;\\&quot;\\&quot;\\n        if not self.running:\\n            # \\u5982\\u679c\\u6ca1\\u5728\\u8fd0\\u884c\\uff0c\\u4f46\\u70b9\\u51fb\\u4e86\\u201c\\u91cd\\u65b0\\u5f00\\u59cb\\u201d\\uff0c\\u5219\\u76f4\\u63a5\\u6267\\u884c\\u4e00\\u6b21\\u5f00\\u59cb\\u903b\\u8f91\\n            self.start()\\n            return\\n        self.reset_flag = True # &lt;--- \\u8fd9\\u4e2a\\u6807\\u5fd7\\u53ea\\u7531\\u201c\\u91cd\\u65b0\\u5f00\\u59cb\\u201d\\u6309\\u94ae\\u8bbe\\u7f6e\\n        self.user_active_event.set() # \\u89e6\\u53d1\\u7528\\u6237\\u6d3b\\u52a8\\u4e8b\\u4ef6\\uff0c\\u89e3\\u9664\\u4efb\\u4f55\\u7b49\\u5f85\\u72b6\\u6001\\n        \\n        # \\u91cd\\u7f6e\\u6240\\u6709\\u68c0\\u6d4b\\u5668\\u7684\\u72b6\\u6001\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n\\n        self.waiting_for_user_after_bell = False # \\u53d6\\u6d88\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\n\\n    def stop(self):\\n        \\&quot;\\&quot;\\&quot;\\u505c\\u6b62\\u7a0b\\u5e8f\\u7684\\u8fd0\\u884c\\&quot;\\&quot;\\&quot;\\n        if not self.running:\\n            return\\n        self.running = False # \\u8bbe\\u7f6e\\u8fd0\\u884c\\u6807\\u5fd7\\u4e3aFalse\\uff0c\\u7ec8\\u6b62\\u4e3b\\u5faa\\u73af\\n        self.stop_flag = True # \\u8bbe\\u7f6e\\u505c\\u6b62\\u6807\\u5fd7\\n        self.user_active_event.set() # \\u89e6\\u53d1\\u7528\\u6237\\u6d3b\\u52a8\\u4e8b\\u4ef6\\uff0c\\u89e3\\u9664\\u4efb\\u4f55\\u963b\\u585e\\n        self.stop_listeners() # \\u786e\\u4fdd\\u505c\\u6b62\\u6240\\u6709\\u76d1\\u542c\\u5668\\n\\n        # \\u5728\\u4e3b\\u7ebf\\u7a0b\\u66f4\\u65b0UI\\u72b6\\u6001\\n        self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u5df2\\u505c\\u6b62\\&quot;))\\n        self.root.after(0, lambda: self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n        self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u542f\\u7528\\&quot;))\\n        self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u672a\\u542f\\u7528\\&quot;))\\n        self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n        \\n        # \\u66f4\\u65b0\\u6309\\u94ae\\u6587\\u672c\\n        self.root.after(0, lambda: self.start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n\\n        # \\u505c\\u6b62\\u65f6\\u91cd\\u7f6e\\u6240\\u6709\\u72b6\\u6001\\n        self.waiting_for_user_after_bell = False\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n\\n\\n    def run_timer(self, active_tab_name):\\n        \\&quot;\\&quot;\\&quot;\\u4e3b\\u8ba1\\u65f6\\u903b\\u8f91\\uff0c\\u5728\\u5355\\u72ec\\u7684\\u7ebf\\u7a0b\\u4e2d\\u8fd0\\u884c\\&quot;\\&quot;\\&quot;\\n        print(f\\&quot;[{time.time()}] run_timer \\u7ebf\\u7a0b\\u542f\\u52a8. \\u5f53\\u524d\\u54cd\\u94c3\\u6b21\\u6570: {self.current_count}\\\/{self.total_times}\\&quot;) # Debugging print\\n        while self.current_count &lt;= self.total_times and not self.stop_flag:\\n            # \\u5728\\u4e3b\\u7ebf\\u7a0b\\u66f4\\u65b0\\u5f53\\u524d\\u6b21\\u6570\\n            self.root.after(0, lambda: self.status_label.config(text=f\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a{self.current_count} \\\/ {self.total_times}\\&quot;))\\n            \\n            should_ring_this_cycle = False # \\u6807\\u8bb0\\u5f53\\u524d\\u5468\\u671f\\u662f\\u5426\\u5e94\\u8be5\\u54cd\\u94c3\\n            user_interrupted_cycle_during_normal_detection = False # \\u65b0\\u589e\\u6807\\u5fd7\\uff1a\\u5728\\u6b63\\u5e38\\u68c0\\u6d4b\\u4e2d\\u7528\\u6237\\u662f\\u5426\\u4e2d\\u65ad\\u4e86\\u5f53\\u524d\\u5468\\u671f\\n\\n            # --- \\u54cd\\u94c3\\u540e\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\u72b6\\u6001 (\\u4ec5\\u5728\\u7279\\u5b9a\\u6a21\\u5f0f\\u4e0b) ---\\n            if self.waiting_for_user_after_bell:\\n                self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                print(f\\&quot;[{time.time()}] \\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001.\\&quot;) # Debugging print\\n                \\n                # \\u66f4\\u65b0\\u5bf9\\u5e94\\u6a21\\u5f0f\\u7684\\u72b6\\u6001\\u6807\\u7b7e\\n                if active_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                    self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u54cd\\u94c3\\u540e\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\&quot;, fg=\\&quot;orange\\&quot;))\\n                elif active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                    self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u54cd\\u94c3\\u540e\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u91cd\\u7f6e\\&quot;, fg=\\&quot;orange\\&quot;))\\n                    self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n                \\n                self.user_active_event.clear() # \\u6e05\\u9664\\u4efb\\u4f55\\u5386\\u53f2\\u7528\\u6237\\u6d3b\\u52a8\\u4e8b\\u4ef6\\uff0c\\u786e\\u4fdd\\u53ea\\u54cd\\u5e94\\u65b0\\u7684\\u64cd\\u4f5c\\n                \\n                # \\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u3001\\u505c\\u6b62\\u6307\\u4ee4\\u6216\\u91cd\\u7f6e\\u6307\\u4ee4\\n                while not self.stop_flag and not self.reset_flag and not self.user_active_event.is_set():\\n                    time.sleep(0.1) # \\u77ed\\u6682\\u4f11\\u7720\\uff0c\\u907f\\u514d\\u9ad8CPU\\u5360\\u7528\\n                \\n                if self.user_active_event.is_set(): # \\u5982\\u679c\\u662f\\u7528\\u6237\\u64cd\\u4f5c\\uff08\\u9f20\\u6807\\\/\\u952e\\u76d8\\uff09\\u89e6\\u53d1\\u4e86\\u91cd\\u7f6e\\n                    print(f\\&quot;[{time.time()}] \\u7528\\u6237\\u64cd\\u4f5c\\u89e3\\u9664\\u7b49\\u5f85\\u72b6\\u6001.\\&quot;) # Debugging print\\n                    self.user_active_event.clear() # \\u6e05\\u9664\\u4e8b\\u4ef6\\n                    self.waiting_for_user_after_bell = False # \\u9000\\u51fa\\u7b49\\u5f85\\u72b6\\u6001\\n                    if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;: # \\u9f20\\u6807\\u79fb\\u52a8\\u540e\\uff0c\\u7f51\\u901f\\u68c0\\u6d4b\\u91cd\\u65b0\\u7b49\\u5f85\\u5927\\u6d41\\u91cf\\n                        self.network_detector.awaiting_significant_traffic = True\\n                    continue # \\u91cd\\u65b0\\u5f00\\u59cb\\u5916\\u5c42\\u5faa\\u73af\\uff0c\\u76f4\\u63a5\\u8fdb\\u5165\\u5e38\\u89c4\\u8ba1\\u65f6\\u903b\\u8f91\\uff08\\u4e0d\\u91cd\\u7f6e\\u54cd\\u94c3\\u6b21\\u6570\\uff09\\n                \\n                # \\u5982\\u679c\\u4ee3\\u7801\\u6267\\u884c\\u5230\\u8fd9\\u91cc\\uff0c\\u8bf4\\u660e\\u4e0d\\u662f\\u7528\\u6237\\u64cd\\u4f5c\\u89e3\\u9664\\u7b49\\u5f85\\uff0c\\u800c\\u662f stop_flag \\u6216 reset_flag \\u88ab\\u8bbe\\u7f6e\\u4e86\\n                if self.reset_flag: # \\u65e0\\u8bba\\u662f\\u7528\\u6237\\u70b9\\u51fb\\u201c\\u91cd\\u65b0\\u5f00\\u59cb\\u201d\\u6309\\u94ae\\n                    print(f\\&quot;[{time.time()}] Reset \\u6309\\u94ae\\u88ab\\u70b9\\u51fb\\uff0c\\u91cd\\u7f6e\\u4efb\\u52a1.\\&quot;) # Debugging print\\n                    self.current_count = 1\\n                    self.reset_flag = False\\n                    self.region_detector.reset_state() # \\u91cd\\u7f6e\\u533a\\u57df\\u6697\\u8272\\u72b6\\u6001\\n                    self.network_detector.reset_state() # \\u91cd\\u7f6e\\u7f51\\u901f\\u68c0\\u6d4b\\u72b6\\u6001\\n                    self.timer_detector.reset_state()\\n                    self.waiting_for_user_after_bell = False # \\u91cd\\u7f6e\\u4e5f\\u53d6\\u6d88\\u7b49\\u5f85\\u72b6\\u6001\\n                    continue # \\u91cd\\u65b0\\u5f00\\u59cb\\u5916\\u5c42\\u5faa\\u73af (\\u56de\\u5230\\u8ba1\\u65f6\\u5f00\\u59cb)\\n                \\n                if self.stop_flag: # \\u5982\\u679c\\u70b9\\u51fb\\u4e86\\u201c\\u505c\\u6b62\\u201d\\u6309\\u94ae\\n                    print(f\\&quot;[{time.time()}] Stop \\u6309\\u94ae\\u88ab\\u70b9\\u51fb\\uff0c\\u505c\\u6b62\\u4efb\\u52a1.\\&quot;) # Debugging print\\n                    break # \\u6574\\u4e2a\\u7a0b\\u5e8f\\u505c\\u6b62\\n\\n            # --- \\u5e38\\u89c4\\u8ba1\\u65f6\\u903b\\u8f91 (\\u5982\\u679c\\u4e0d\\u5728\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001) ---\\n            self.start_cycle_time = time.time() # \\u8bb0\\u5f55\\u5f53\\u524d\\u5faa\\u73af\\u7684\\u5f00\\u59cb\\u65f6\\u95f4\\n            print(f\\&quot;[{time.time()}] \\u8fdb\\u5165\\u5e38\\u89c4\\u68c0\\u6d4b\\u5468\\u671f. \\u5468\\u671f\\u5f00\\u59cb\\u65f6\\u95f4: {self.start_cycle_time}\\&quot;) # Debugging print\\n            \\n            while True: # \\u5185\\u90e8\\u5faa\\u73af\\uff1a\\u4e00\\u4e2a\\u5b8c\\u6574\\u7684\\u68c0\\u6d4b\\u5468\\u671f\\n                if self.stop_flag or self.reset_flag: # \\u5168\\u5c40\\u505c\\u6b62\\u6216\\u91cd\\u7f6e\\uff0c\\u9000\\u51fa\\u5f53\\u524d\\u5185\\u90e8\\u5faa\\u73af\\n                    print(f\\&quot;[{time.time()}] \\u68c0\\u6d4b\\u5468\\u671f\\u88ab\\u505c\\u6b62\\u6216\\u91cd\\u7f6e\\u6807\\u5fd7\\u6253\\u65ad.\\&quot;) # Debugging print\\n                    break\\n                \\n                # \\u68c0\\u67e5\\u7528\\u6237\\u6d3b\\u52a8\\uff0c\\u5982\\u679c\\u53d1\\u751f\\uff0c\\u5219\\u91cd\\u65b0\\u5f00\\u59cb\\u5f53\\u524d\\u5468\\u671f\\uff08\\u975e\\u5b8c\\u5168\\u91cd\\u7f6e\\uff09\\n                if self.user_active_event.wait(timeout=0.1): # \\u6bcf\\u6b21\\u5faa\\u73af\\u90fd\\u5feb\\u901f\\u68c0\\u67e5\\u7528\\u6237\\u6d3b\\u52a8\\n                    self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u23f1 \\u7528\\u6237\\u64cd\\u4f5c\\uff0c\\u91cd\\u65b0\\u8ba1\\u65f6\\&quot;))\\n                    print(f\\&quot;[{time.time()}] \\u7528\\u6237\\u64cd\\u4f5c\\uff0c\\u91cd\\u65b0\\u5f00\\u59cb\\u5f53\\u524d\\u68c0\\u6d4b\\u5468\\u671f.\\&quot;) # Debugging print\\n                    self.user_active_event.clear() # \\u6e05\\u9664\\u4e8b\\u4ef6\\uff0c\\u51c6\\u5907\\u4e0b\\u4e00\\u6b21\\u68c0\\u6d4b\\n                    user_interrupted_cycle_during_normal_detection = True # \\u6807\\u8bb0\\u4e3a\\u7528\\u6237\\u4e2d\\u65ad\\u4e86\\u5f53\\u524d\\u5468\\u671f\\n                    break # \\u8df3\\u51fa\\u5f53\\u524d\\u5185\\u90e8\\u5faa\\u73af\\n\\n                # \\u6839\\u636e\\u5f53\\u524d\\u6a21\\u5f0f\\u6267\\u884c\\u4e0d\\u540c\\u7684\\u68c0\\u6d4b\\u903b\\u8f91\\n                if self.active_detector:\\n                    should_ring_this_cycle, status_message = self.active_detector.check_condition()\\n                    self.root.after(0, lambda: self.countdown_label.config(text=self.active_detector.get_display_info()))\\n                    \\n                    if should_ring_this_cycle: # \\u68c0\\u6d4b\\u6761\\u4ef6\\u6ee1\\u8db3\\uff0c\\u9700\\u8981\\u54cd\\u94c3\\n                        print(f\\&quot;[{time.time()}] \\u68c0\\u6d4b\\u6761\\u4ef6\\u6ee1\\u8db3\\uff0c\\u51c6\\u5907\\u54cd\\u94c3.\\&quot;) # Debugging print\\n                        break # \\u8df3\\u51fa\\u5f53\\u524d\\u5185\\u90e8\\u5faa\\u73af\\uff0c\\u8fdb\\u5165\\u54cd\\u94c3\\u903b\\u8f91\\n                    \\n                    # \\u6839\\u636e\\u4e0d\\u540c\\u6a21\\u5f0f\\u8bbe\\u7f6e\\u68c0\\u6d4b\\u95f4\\u9694\\n                    if active_tab_name == \\&quot;\\u533a\\u57df\\u989c\\u8272\\u68c0\\u6d4b\\&quot;:\\n                        time.sleep(1) # \\u6bcf\\u79d2\\u68c0\\u6d4b\\u4e00\\u6b21\\u4eae\\u5ea6\\n                    elif active_tab_name == \\&quot;\\u56fa\\u5b9a\\u65f6\\u95f4\\u54cd\\u94c3\\&quot;:\\n                        time.sleep(1) # \\u6bcf\\u79d2\\u66f4\\u65b0\\u4e00\\u6b21\\u5012\\u8ba1\\u65f6\\n                    elif active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                        # \\u7f51\\u901f\\u68c0\\u6d4b\\u95f4\\u9694\\u7531\\u7528\\u6237\\u8bbe\\u5b9a\\n                        sleep_interval = int(self.check_interval_sec_var.get())\\n                        time.sleep(sleep_interval)\\n                        print(f\\&quot;[{time.time()}] \\u7f51\\u901f\\u68c0\\u6d4b\\uff0c\\u4f11\\u7720 {sleep_interval} \\u79d2.\\&quot;) # Debugging print\\n\\n            # --- \\u5904\\u7406\\u5185\\u90e8\\u5faa\\u73af\\u9000\\u51fa\\u7684\\u539f\\u56e0 ---\\n            if self.stop_flag: # \\u5982\\u679c\\u662f\\u201c\\u505c\\u6b62\\u201d\\u6309\\u94ae\\u5bfc\\u81f4\\u7684\\u9000\\u51fa\\n                print(f\\&quot;[{time.time()}] \\u5185\\u90e8\\u5faa\\u73af\\u56e0 Stop \\u6807\\u5fd7\\u9000\\u51fa.\\&quot;) # Debugging print\\n                break # \\u6574\\u4e2a\\u7a0b\\u5e8f\\u505c\\u6b62\\n            \\n            if self.reset_flag: # \\u5982\\u679c\\u662f\\u201c\\u91cd\\u65b0\\u5f00\\u59cb\\u201d\\u6309\\u94ae\\u5bfc\\u81f4\\u7684\\u9000\\u51fa\\uff08\\u5b8c\\u5168\\u91cd\\u7f6e\\uff09\\n                print(f\\&quot;[{time.time()}] \\u5185\\u90e8\\u5faa\\u73af\\u56e0 Reset \\u6807\\u5fd7\\u9000\\u51fa\\uff0c\\u6267\\u884c\\u5b8c\\u5168\\u91cd\\u7f6e.\\&quot;) # Debugging print\\n                self.current_count = 1\\n                self.reset_flag = False\\n                self.user_active_event.clear()\\n                self.region_detector.reset_state() # \\u91cd\\u7f6e\\u533a\\u57df\\u6697\\u8272\\u72b6\\u6001\\n                self.network_detector.reset_state() # \\u91cd\\u7f6e\\u7f51\\u901f\\u68c0\\u6d4b\\u72b6\\u6001\\n                self.timer_detector.reset_state()\\n                self.waiting_for_user_after_bell = False # \\u91cd\\u7f6e\\u4e5f\\u53d6\\u6d88\\u7b49\\u5f85\\u72b6\\u6001\\n                continue # \\u91cd\\u65b0\\u5f00\\u59cb\\u5916\\u5c42\\u5faa\\u73af (\\u56de\\u5230\\u8ba1\\u65f6\\u5f00\\u59cb)\\n            \\n            if user_interrupted_cycle_during_normal_detection: # \\u5982\\u679c\\u662f\\u7528\\u6237\\u5728\\u6b63\\u5e38\\u68c0\\u6d4b\\u4e2d\\u64cd\\u4f5c\\u5bfc\\u81f4\\u7684\\u9000\\u51fa\\uff08\\u53ea\\u91cd\\u65b0\\u5f00\\u59cb\\u5f53\\u524d\\u5468\\u671f\\uff09\\n                print(f\\&quot;[{time.time()}] \\u5185\\u90e8\\u5faa\\u73af\\u56e0\\u7528\\u6237\\u64cd\\u4f5c\\u9000\\u51fa\\uff0c\\u91cd\\u65b0\\u5f00\\u59cb\\u5f53\\u524d\\u5468\\u671f.\\&quot;) # Debugging print\\n                # \\u8fd9\\u610f\\u5473\\u7740\\u6211\\u4eec\\u53ea\\u662f\\u91cd\\u65b0\\u5f00\\u59cb\\u5f53\\u524d\\u5468\\u671f\\uff0c\\u4e0d\\u589e\\u52a0\\u54cd\\u94c3\\u6b21\\u6570\\n                continue # \\u91cd\\u65b0\\u5f00\\u59cb\\u5916\\u5c42\\u5faa\\u73af\\uff0c`self.start_cycle_time` \\u4f1a\\u88ab\\u91cd\\u65b0\\u8bbe\\u7f6e\\n\\n            # --- \\u54cd\\u94c3\\u903b\\u8f91 (\\u53ea\\u6709\\u5f53 `should_ring_this_cycle` \\u4e3a True \\u4e14\\u6ca1\\u6709\\u88ab\\u4e2d\\u65ad\\u6216\\u91cd\\u7f6e\\u65f6\\u6267\\u884c) ---\\n            if should_ring_this_cycle:\\n                print(f\\&quot;[{time.time()}] \\u5f00\\u59cb\\u54cd\\u94c3\\u903b\\u8f91. \\u6a21\\u5f0f: {self.mode_var.get()}\\&quot;) # Debugging print\\n                set_system_volume(self.volume_var.get()) # \\u8bbe\\u7f6e\\u7cfb\\u7edf\\u97f3\\u91cf\\n                \\n                bell_mode_val = self.mode_var.get()\\n                \\n                if bell_mode_val == \\&quot;continuous\\&quot;: # \\u6301\\u7eed\\u54cd\\u94c3\\u6a21\\u5f0f\\n                    self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\\\U0001F514 \\u6301\\u7eed\\u54cd\\u94c3\\u4e2d\\uff08\\u8bf7\\u64cd\\u4f5c\\u9f20\\u6807\\u952e\\u76d8\\u7ec8\\u6b62\\uff09\\&quot;))\\n                    self.user_active_event.clear() # \\u6e05\\u9664\\u54cd\\u94c3\\u524d\\u7684\\u7528\\u6237\\u6d3b\\u52a8\\u6807\\u5fd7\\n                    \\n                    continuous_bell_start_time = time.time()\\n                    continuous_bell_duration = int(self.continuous_bell_duration_var.get())\\n                    \\n                    while not self.user_active_event.is_set() and not self.stop_flag and not self.reset_flag:\\n                        play_bell_sound() # \\u6301\\u7eed\\u54cd\\u94c3\\u53ea\\u54cd\\u4e00\\u58f0\\n                        if time.time() - continuous_bell_start_time &gt;= continuous_bell_duration: \\n                            self.root.after(0, lambda dur=continuous_bell_duration: self.countdown_label.config(text=f\\&quot;\\ud83d\\udd14 \\u54cd\\u94c3{dur}\\u79d2\\uff0c\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c...\\&quot;))\\n                            self.waiting_for_user_after_bell = True # \\u54cd\\u94c3\\u65f6\\u95f4\\u5230\\uff0c\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\n                            print(f\\&quot;[{time.time()}] \\u6301\\u7eed\\u54cd\\u94c3\\u65f6\\u95f4\\u5230\\uff0c\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c.\\&quot;) # Debugging print\\n                            break # \\u8df3\\u51fa\\u54cd\\u94c3\\u5faa\\u73af\\n                        if self.user_active_event.wait(timeout=1): # \\u51cf\\u5c11\\u7b49\\u5f85\\u65f6\\u95f4\\uff0c\\u66f4\\u7075\\u654f\\n                            print(f\\&quot;[{time.time()}] \\u7528\\u6237\\u64cd\\u4f5c\\u4e2d\\u65ad\\u6301\\u7eed\\u54cd\\u94c3.\\&quot;) # Debugging print\\n                            break # \\u7528\\u6237\\u64cd\\u4f5c\\uff0c\\u8df3\\u51fa\\u54cd\\u94c3\\u5faa\\u73af\\n\\n                    # \\u54cd\\u94c3\\u5faa\\u73af\\u4e2d\\u65ad\\u540e\\uff0c\\u5224\\u65ad\\u539f\\u56e0\\n                    if self.user_active_event.is_set(): # \\u5982\\u679c\\u662f\\u7528\\u6237\\u64cd\\u4f5c\\uff08\\u9f20\\u6807\\\/\\u952e\\u76d8\\uff09\\u4e2d\\u65ad\\u4e86\\u54cd\\u94c3\\n                        self.user_active_event.clear() # \\u6e05\\u9664\\u4e8b\\u4ef6\\n                        self.waiting_for_user_after_bell = True # \\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\n                        if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;: # \\u9f20\\u6807\\u79fb\\u52a8\\u540e\\uff0c\\u7f51\\u901f\\u68c0\\u6d4b\\u91cd\\u65b0\\u7b49\\u5f85\\u5927\\u6d41\\u91cf\\n                            self.network_detector.awaiting_significant_traffic = True\\n                        continue # \\u56de\\u5230\\u5916\\u5c42\\u5faa\\u73af\\u9876\\u90e8\\uff0c\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u7684\\u5206\\u652f\\n                    elif self.reset_flag: # \\u88ab\\u201c\\u91cd\\u65b0\\u5f00\\u59cb\\u201d\\u6309\\u94ae\\u91cd\\u7f6e\\n                        # \\u6b64\\u65f6 reset_flag \\u5df2\\u7ecf\\u8bbe\\u7f6e\\uff0c\\u5916\\u5c42\\u5faa\\u73af\\u7684 reset_flag \\u68c0\\u67e5\\u4f1a\\u5904\\u7406\\u5b83\\n                        continue \\n                    elif self.stop_flag: # \\u88ab\\u201c\\u505c\\u6b62\\u201d\\u6309\\u94ae\\u505c\\u6b62\\n                        break\\n                    # \\u5982\\u679c\\u54cd\\u94c3\\u65f6\\u95f4\\u5230\\u81ea\\u52a8\\u505c\\u6b62\\uff0c\\u4e14\\u672a\\u88ab\\u7528\\u6237\\u64cd\\u4f5c\\u3001\\u505c\\u6b62\\u6216\\u91cd\\u7f6e\\u6253\\u65ad\\uff0c\\u5219\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001 (waiting_for_user_after_bell\\u5df2\\u5728\\u6b64\\u5206\\u652f\\u4e2d\\u8bbe\\u7f6e)\\n                    if self.waiting_for_user_after_bell: # \\u53ea\\u6709\\u5f53\\u8ba1\\u65f6\\u5668\\u5230\\u65f6\\u81ea\\u52a8\\u505c\\u6b62\\u65f6\\u624d\\u9700\\u8981\\u989d\\u5916\\u5904\\u7406\\n                         if active_tab_name == \\&quot;\\u7f51\\u901f\\u68c0\\u6d4b\\&quot;:\\n                             self.network_detector.awaiting_significant_traffic = True\\n                         continue # \\u56de\\u5230\\u5916\\u5c42\\u5faa\\u73af\\u9876\\u90e8\\uff0c\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u7684\\u5206\\u652f\\n\\n\\n                else: # \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\n                    self.root.after(0, lambda: self.countdown_label.config(text=f\\&quot;\\\\U0001F514 \\u54cd\\u94c3 1 \\u6b21\\&quot;))\\n                    print(f\\&quot;[{time.time()}] \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\uff0c\\u64ad\\u653e\\u54cd\\u94c3.\\&quot;) # Debugging print\\n                    \\n                    # \\u54cd\\u94c31\\u6b21\\n                    play_bell_sound() \\n                    # \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u4e0b\\uff0c\\u54cd\\u94c3\\u540e\\u6682\\u505c2\\u79d2\\uff0c\\u540c\\u65f6\\u76d1\\u542c\\u7528\\u6237\\u6d3b\\u52a8\\u4ee5\\u8fdb\\u5165\\u7b49\\u5f85\\u72b6\\u6001\\n                    # \\u79fb\\u9664\\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u540e\\u7684\\u5f3a\\u5236\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\uff0c\\u53ea\\u7b49\\u5f85\\u54cd\\u94c3\\u58f0\\u7ed3\\u675f\\n                    # \\u5982\\u679c\\u7528\\u6237\\u5728\\u54cd\\u94c3\\u7ed3\\u675f\\u540e\\u7acb\\u5373\\u64cd\\u4f5c\\uff0c\\u5219\\u4f1a\\u91cd\\u65b0\\u5f00\\u59cb\\u5468\\u671f\\n                    if self.user_active_event.wait(timeout=0.5): # \\u77ed\\u6682\\u7b49\\u5f85\\uff0c\\u786e\\u4fdd\\u54cd\\u94c3\\u5b8c\\u6210\\uff0c\\u540c\\u65f6\\u68c0\\u6d4b\\u7528\\u6237\\u64cd\\u4f5c\\n                        print(f\\&quot;[{time.time()}] \\u7528\\u6237\\u64cd\\u4f5c\\u5728\\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u54cd\\u94c3\\u540e\\u7acb\\u5373\\u53d1\\u751f.\\&quot;) # Debugging print\\n                        self.user_active_event.clear()\\n                        user_interrupted_cycle_during_normal_detection = True # \\u6807\\u8bb0\\u4e3a\\u7528\\u6237\\u5728\\u54cd\\u94c3\\u8fc7\\u7a0b\\u4e2d\\u4e2d\\u65ad\\n                        continue # \\u56de\\u5230\\u5916\\u5c42\\u5faa\\u73af\\u9876\\u90e8\\uff0c`user_interrupted_cycle_during_normal_detection` \\u4f1a\\u5bfc\\u81f4\\u5468\\u671f\\u91cd\\u542f\\n                    \\n                    # \\u5982\\u679c\\u54cd\\u94c3\\u5b8c\\u6210\\u4e14\\u672a\\u88ab\\u4e2d\\u65ad\\uff0c\\u5219\\u7ee7\\u7eed\\u6267\\u884c\\u540e\\u7eed\\u903b\\u8f91\\uff0c\\u4e0d\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\n                    print(f\\&quot;[{time.time()}] \\u54cd\\u4e00\\u4e0b\\u6a21\\u5f0f\\u54cd\\u94c3\\u5b8c\\u6210.\\&quot;) # Debugging print\\n\\n                # \\u53ea\\u6709\\u5f53\\u54cd\\u94c3\\u6b63\\u5e38\\u5b8c\\u6210\\uff08\\u6ca1\\u6709\\u8fdb\\u5165\\u7b49\\u5f85\\u7528\\u6237\\u64cd\\u4f5c\\u72b6\\u6001\\uff0c\\u4e5f\\u6ca1\\u6709\\u56e0\\u4e3a\\u7528\\u6237\\u5728\\u68c0\\u6d4b\\u9636\\u6bb5\\u6216\\u54cd\\u94c3\\u4e2d\\u9014\\u64cd\\u4f5c\\u800c\\u4e2d\\u65ad\\u5e76\\u91cd\\u542f\\u5468\\u671f\\uff09\\n                # \\u624d\\u4f1a\\u589e\\u52a0\\u54cd\\u94c3\\u6b21\\u6570\\u5e76\\u8fdb\\u5165\\u4e0b\\u4e00\\u4e2a\\u5468\\u671f\\n                if not self.waiting_for_user_after_bell and not user_interrupted_cycle_during_normal_detection:\\n                    self.current_count += 1\\n                    print(f\\&quot;[{time.time()}] \\u54cd\\u94c3\\u6b21\\u6570\\u589e\\u52a0\\u5230 {self.current_count}.\\&quot;) # Debugging print\\n                \\n                # \\u54cd\\u94c3\\u7ed3\\u675f\\u540e\\u6e05\\u9664\\u7528\\u6237\\u6d3b\\u52a8\\u6807\\u5fd7\\uff0c\\u4e3a\\u4e0b\\u4e00\\u4e2a\\u5468\\u671f\\u505a\\u51c6\\u5907\\n                self.user_active_event.clear() \\n\\n        # \\u4e3b\\u5faa\\u73af\\u7ed3\\u675f\\u65f6\\u7684\\u6e05\\u7406\\u5de5\\u4f5c\\n        self.running = False\\n        self.stop_listeners()\\n        print(f\\&quot;[{time.time()}] run_timer \\u7ebf\\u7a0b\\u7ed3\\u675f.\\&quot;) # Debugging print\\n\\n        if not self.stop_flag: # \\u5982\\u679c\\u4e0d\\u662f\\u4e3b\\u52a8\\u70b9\\u51fb\\u505c\\u6b62\\u6309\\u94ae\\uff0c\\u800c\\u662f\\u4efb\\u52a1\\u5b8c\\u6210\\n            self.root.after(0, lambda: self.countdown_label.config(text=\\&quot;\\u2705 \\u5b8c\\u6210\\&quot;))\\n            self.root.after(0, lambda: self.status_label.config(text=\\&quot;\\u5f53\\u524d\\u6b21\\u6570\\uff1a-- \\\/ --\\&quot;))\\n            self.root.after(0, lambda: self.region_status_label.config(text=\\&quot;\\u533a\\u57df\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7ed3\\u675f\\&quot;))\\n            self.root.after(0, lambda: self.network_status_label.config(text=\\&quot;\\u7f51\\u901f\\u76d1\\u6d4b\\u72b6\\u6001\\uff1a\\u7ed3\\u675f\\&quot;))\\n            self.root.after(0, lambda: self.current_speed_label.config(text=\\&quot;\\u5f53\\u524d\\u4e0b\\u8f7d\\u901f\\u5ea6\\uff1a-- KB\\\/S\\&quot;))\\n        \\n        # \\u65e0\\u8bba\\u5982\\u4f55\\uff0c\\u5728\\u7a0b\\u5e8f\\u6700\\u7ec8\\u505c\\u6b62\\u65f6\\uff0c\\u91cd\\u7f6e\\u6240\\u6709\\u72b6\\u6001\\u5e76\\u66f4\\u65b0\\u6309\\u94ae\\u6587\\u672c\\n        self.waiting_for_user_after_bell = False\\n        self.region_detector.reset_state()\\n        self.network_detector.reset_state()\\n        self.timer_detector.reset_state()\\n        self.root.after(0, lambda: self.start_stop_btn.config(text=\\&quot;\\u5f00\\u59cb\\&quot;))\\n\\n\\nif __name__ == \\&quot;__main__\\&quot;:\\n    root = tk.Tk()\\n    try:\\n        app = BellApp(root)\\n        root.mainloop()\\n    except Exception as e:\\n        # \\u6355\\u83b7\\u4e3b\\u7ebf\\u7a0b\\u7684\\u4efb\\u4f55\\u672a\\u5904\\u7406\\u5f02\\u5e38\\n        error_message = f\\&quot;\\u7a0b\\u5e8f\\u53d1\\u751f\\u610f\\u5916\\u9519\\u8bef\\uff1a\\\\n{e}\\\\n\\\\n\\u8be6\\u7ec6\\u4fe1\\u606f\\u8bf7\\u67e5\\u770b\\u63a7\\u5236\\u53f0\\u3002\\&quot;\\n        print(\\&quot;\\\\n\\&quot; + \\&quot;=\\&quot;*50)\\n        print(\\&quot;\\u7a0b\\u5e8f\\u53d1\\u751f\\u672a\\u6355\\u83b7\\u7684\\u9519\\u8bef\\uff01\\&quot;)\\n        traceback.print_exc() # \\u6253\\u5370\\u5b8c\\u6574\\u7684 traceback \\u5230\\u63a7\\u5236\\u53f0\\n        print(\\&quot;=\\&quot;*50 + \\&quot;\\\\n\\&quot;)\\n        messagebox.showerror(\\&quot;\\u7a0b\\u5e8f\\u9519\\u8bef\\&quot;, error_message)\\n        sys.exit(1)&quot;,&quot;codeTypo&quot;:{&quot;desktop&quot;:9,&quot;tablet&quot;:15,&quot;mobile&quot;:14},&quot;height&quot;:{&quot;desktop&quot;:&quot;500px&quot;,&quot;tablet&quot;:&quot;0px&quot;,&quot;mobile&quot;:&quot;0px&quot;},&quot;align&quot;:&quot;&quot;,&quot;lineNumbers&quot;:true,&quot;theme&quot;:&quot;default&quot;,&quot;clipBoard&quot;:true,&quot;wordWrap&quot;:true,&quot;width&quot;:{&quot;desktop&quot;:&quot;100%&quot;,&quot;tablet&quot;:&quot;100%&quot;,&quot;mobile&quot;:&quot;100%&quot;},&quot;padding&quot;:{&quot;top&quot;:&quot;0px&quot;,&quot;right&quot;:&quot;0px&quot;,&quot;bottom&quot;:&quot;0px&quot;,&quot;left&quot;:&quot;0px&quot;},&quot;background&quot;:{&quot;color&quot;:&quot;#d3cfcf42&quot;},&quot;layout&quot;:{&quot;align&quot;:&quot;left&quot;},&quot;border&quot;:{&quot;color&quot;:&quot;#000&quot;,&quot;style&quot;:&quot;solid&quot;,&quot;width&quot;:&quot;0px&quot;},&quot;shadow&quot;:[],&quot;alignment&quot;:&quot;center&quot;,&quot;clipBoardColors&quot;:{&quot;color&quot;:&quot;#fff&quot;,&quot;bg&quot;:&quot;#00000024&quot;}}'><\/div>\r\n\r\n\t\t\n\n\n<h1 class=\"wp-block-heading\">\u5f85\u6539\u8fdb\u4e4b\u5904<\/h1>\n\n\n\n<p>V7.3<\/p>\n\n\n\n<p>\u56fa\u5b9a\u65f6\u95f4\u54cd\u94c3 \u548c \u7f51\u901f\u68c0\u6d4b\u9009\u9879\u5361\u4e0b\uff0c\u52a0\u51e0\u4e2a\u5355\u9009\u6846\uff1a<\/p>\n\n\n\n<p>1\u3001\u9f20\u6807\u79fb\u52a8\u540e\u91cd\u65b0\u68c0\u6d4b\uff08\u9ed8\u8ba4\u9009\u4e2d\uff09\uff1b<\/p>\n\n\n\n<p>2\u3001\u9f20\u6807\u9009\u4e2d\u672c\u7a97\u53e3\u540e\u91cd\u65b0\u68c0\u6d4b\uff1b<\/p>\n\n\n\n<p>3\u3001\u4e0d\u91cd\u65b0\u68c0\u6d4b\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading has-text-align-center\">\u5728Windows 7\u4e2d\u4f7f\u7528<\/h1>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li><strong>\u5728 Windows 7 \u73af\u5883\u4e0b\u5b89\u88c5 Python 3.8\u3002<\/strong><\/li>\n\n\n\n<li><strong>\u5728\u8be5 Python 3.8 \u73af\u5883\u4e2d\u5b89\u88c5\u6240\u6709\u6240\u9700\u7684\u5e93\uff1a<\/strong>Bash<code>pip install playsound pynput psutil Pillow pycaw<\/code><\/li>\n\n\n\n<li><strong>\u5728\u8be5 Python 3.8 \u73af\u5883\u4e2d\u5b89\u88c5 PyInstaller\uff1a<\/strong>Bash<code>pip install pyinstaller<\/code><\/li>\n\n\n\n<li><strong>\u5728 Windows 7 \u4e0a\u4f7f\u7528 PyInstaller \u6253\u5305\u60a8\u7684\u811a\u672c\uff1a<\/strong>Bash<code>pyinstaller -F -w 7.3.py <\/code><\/li>\n<\/ol>\n\n\n\n<p>\u901a\u8fc7\u5728\u76ee\u6807\u64cd\u4f5c\u7cfb\u7edf\u73af\u5883\uff08Windows 7 + Python 3.8\uff09\u4e0b\u8fdb\u884c\u6253\u5305\uff0c\u53ef\u4ee5\u6700\u5927\u7a0b\u5ea6\u5730\u786e\u4fdd\u751f\u6210\u7684\u53ef\u6267\u884c\u6587\u4ef6\u5177\u6709\u517c\u5bb9\u6027\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5de5\u5177\u4ecb\u7ecd \u8fd9\u4e2a\u5de5\u5177\u662f\u4e00\u4e2a\u57fa\u4e8e Python \u548c Tkinter \u5f00\u53d1\u7684\u667a\u80fd\u54cd\u94c3\u5668\uff0c\u7528\u4e8e\u5728\u7279\u5b9a\u6761\u4ef6\u4e0b\u89e6\u53d1\u7cfb\u7edf\u63d0\u793a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20,91,5],"tags":[],"class_list":["post-3621","post","type-post","status-publish","format-standard","hentry","category-windows","category-91","category-5"],"_links":{"self":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3621","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3621"}],"version-history":[{"count":7,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3621\/revisions"}],"predecessor-version":[{"id":3721,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=\/wp\/v2\/posts\/3621\/revisions\/3721"}],"wp:attachment":[{"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3621"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.kangyue.pro\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}